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

  1. From: zeppelin@login.dknet.dk (Thomas B. Pedersen)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i059:  typhoon - Typhoon Relational Database Management System, Part03/09
  4. Date: 17 Sep 1994 21:45:26 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <35g9k6$ohf@sparky.sterling.com>
  9. X-Md4-Signature: 523b50b89b972700c8495c636ca5f5fc
  10.  
  11. Submitted-by: zeppelin@login.dknet.dk (Thomas B. Pedersen)
  12. Posting-number: Volume 44, Issue 59
  13. Archive-name: typhoon/part03
  14. Environment: SCO UNIX, Tandem NonStop UNIX, Sun Solaris, AIX, Linux, OS/2
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # Contents:  typhoon/src/bt_del.c typhoon/src/bt_open.c
  21. #   typhoon/src/ty_ins.c typhoon/src/ty_io.c
  22. #   typhoon/src/util/ddlpsym.c typhoon/src/util/imp_y.h
  23. # Wrapped by kent@sparky on Sat Sep 17 21:38:16 1994
  24. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 3 (of 9)."'
  27. if test -f 'typhoon/src/bt_del.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'typhoon/src/bt_del.c'\"
  29. else
  30.   echo shar: Extracting \"'typhoon/src/bt_del.c'\" \(12035 characters\)
  31.   sed "s/^X//" >'typhoon/src/bt_del.c' <<'END_OF_FILE'
  32. X/*----------------------------------------------------------------------------
  33. X * File    : bt_del
  34. X * Library : typhoon
  35. X * OS      : UNIX, OS/2, DOS
  36. X * Author  : Thomas B. Pedersen
  37. X *
  38. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  39. X *
  40. X * Permission is hereby granted, without written agreement and without
  41. X * license or royalty fees, to use, copy, modify, and distribute this
  42. X * software and its documentation for any purpose, provided that the above
  43. X * copyright notice and the following two  paragraphs appear (1) in all 
  44. X * source copies of this software and (2) in accompanying documentation
  45. X * wherever the programatic interface of this software, or any derivative
  46. X * of it, is described.
  47. X *
  48. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  49. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  50. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  51. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  52. X *
  53. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  54. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  55. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  56. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  57. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  58. X *
  59. X * Description:
  60. X *   Contains function for removing a tuple from a B-tree index file.
  61. X *   The algorithm is the one is described in "Data structures in Pascal", 
  62. X *   Horowitz & Sahni, Computer Science Press.
  63. X *
  64. X * Functions:
  65. X *   delchain_insert            - Add a node to the delete chain.
  66. X *   merge_siblings                - Merge two sibling nodes to a single node.
  67. X *   move_parentkey                - Move a parent key to another tuple.
  68. X *   find_ref                    - Find tuple with correct reference.
  69. X *   replace_with_leftmost_tuple- Copy the leftmost tuple in a subtree.
  70. X *   btree_del                    - 
  71. X *
  72. X * $Log: bt_del.c,v $
  73. X * Revision 1.2  1994/09/17  16:00:11  tbp
  74. X * typhoon.h and environ.h are now included from <>.
  75. X *
  76. X * Revision 1.1  1994/09/13  21:28:27  tbp
  77. X * Added to repository.
  78. X * 
  79. X *
  80. X *--------------------------------------------------------------------------*/
  81. X
  82. Xstatic char rcsid[] = "$Id: bt_del.c,v 1.2 1994/09/17 16:00:11 tbp Exp $";
  83. X
  84. X#include <string.h>
  85. X#include <stdio.h>
  86. X#include <fcntl.h>
  87. X#ifndef UNIX
  88. X#    include <io.h>
  89. X#    include <stdlib.h>
  90. X#else
  91. X#    include <unistd.h>
  92. X#    ifdef __STDC__
  93. X#        include <stdlib.h>
  94. X#    endif
  95. X#endif
  96. X#include <typhoon.h>
  97. X#include "ty_dbd.h"
  98. X#include "ty_type.h"
  99. X#include "ty_prot.h"
  100. X#include "ty_glob.h"
  101. X#include "btree.h"
  102. X
  103. X
  104. X/*--------------------------- Function prototypes ---------------------------*/
  105. Xstatic void    delchain_insert        PRM( (INDEX *,    ix_addr); )
  106. Xstatic void merge_siblings        PRM( (INDEX        *I,
  107. X                                      ix_addr    lsib,
  108. X                                      ix_addr    rsib, 
  109. X                                      ix_addr    z,
  110. X                                      int        zi,
  111. X                                      char         *znode,
  112. X                                      ix_addr    *y,
  113. X                                      char        *ynode,
  114. X                                      ix_addr    *p,
  115. X                                      int        *i); )
  116. X
  117. Xstatic void move_parentkey        PRM( (INDEX        *I,
  118. X                                      ix_addr    rsib,
  119. X                                      int        zi,
  120. X                                      ix_addr    z,
  121. X                                      char        *znode,
  122. X                                      ix_addr    y, 
  123. X                                      char        *ynode); )
  124. X
  125. Xstatic find_ref                    PRM( (INDEX        *I,
  126. X                                      ulong        ref,
  127. X                                      ix_addr    *addr,
  128. X                                      int        *idx,
  129. X                                      void        *key); )
  130. X
  131. Xstatic void replace_with_leftmost_tuple
  132. X                                PRM( (INDEX        *I,
  133. X                                      ix_addr    *y, 
  134. X                                      char        *ynode,
  135. X                                      ix_addr    *p,
  136. X                                      int        *i); )
  137. X
  138. X
  139. X/*----------------------------- delchain_insert ----------------------------*\
  140. X *
  141. X * Purpose     : Inserts a deleted B-tree node in the delete chain.
  142. X *
  143. X * Parameters: I        - B-tree index file descriptor.
  144. X *               addr        - Address of node to insert in delete chain.
  145. X *
  146. X * Returns     : Nothing.
  147. X *
  148. X */
  149. X
  150. Xstatic void delchain_insert(I, addr)
  151. XINDEX *I;
  152. Xix_addr addr;
  153. X{
  154. X    lseek(I->fh, (ulong)I->H.nodesize * (ulong)addr, SEEK_SET);
  155. X    write(I->fh, &I->H.first_deleted, sizeof I->H.first_deleted);
  156. X    I->H.first_deleted = addr;
  157. X}
  158. X
  159. X
  160. X
  161. X/*--------------------------------------------------------------------------*\
  162. X *
  163. X * Function  : merge_siblings
  164. X *
  165. X * Purpose   : Merge two siblings nodes.
  166. X *
  167. X * Parameters: I        - Index handle.
  168. X *               lsib        - Address of left sibling node.
  169. X *               rsib        - Address of right sibling node.
  170. X *               z        -
  171. X *               zi        -
  172. X *               znode    -
  173. X *               y        -
  174. X *               ynode    -
  175. X *               p        -
  176. X *               i        -
  177. X *
  178. X * Returns   : Nothing.
  179. X *
  180. X */
  181. Xstatic void merge_siblings(I, lsib, rsib, z, zi, znode, y, ynode, p, i)
  182. XINDEX    *I;
  183. Xix_addr    lsib, rsib, *y, z, *p;
  184. Xint        zi, *i;
  185. Xchar    *znode;
  186. Xchar    *ynode;
  187. X{
  188. X    if( rsib )
  189. X    {
  190. X        /* copy parent key */
  191. X        keycopy(I->node, NSIZE(I->node), znode, zi);
  192. X
  193. X        /* copy sibling keys */
  194. X        tuplecopy(I->node, NSIZE(I->node)+1, ynode, 0, NSIZE(ynode));
  195. X
  196. X        CHILD(I->node,NSIZE(I->node)+1+NSIZE(ynode)) = CHILD(ynode,NSIZE(ynode));
  197. X
  198. X        delchain_insert(I, *p);
  199. X    }
  200. X    else
  201. X    {
  202. X        /* make room for left sibling */
  203. X        tupleins(I->node, 0, NSIZE(ynode)+1);
  204. X
  205. X        /* copy parent key */
  206. X        keycopy(I->node, NSIZE(ynode), znode, zi);
  207. X
  208. X        /* copy sibling keys */
  209. X        tuplecopy(I->node, 0, ynode, 0, NSIZE(ynode));
  210. X
  211. X        CHILD(I->node,NSIZE(ynode)) = CHILD(ynode,NSIZE(ynode));
  212. X        *y = *p;
  213. X
  214. X        delchain_insert(I, lsib);
  215. X    }
  216. X
  217. X    tupledel(znode, zi);            /* remove parent key            */
  218. X    NSIZE(znode)--;
  219. X    NSIZE(I->node) += 1 + NSIZE(ynode);
  220. X
  221. X    nodewrite(I, I->node, *y);
  222. X
  223. X    /* create new root? */
  224. X    if( z == 1 && !NSIZE(znode) )
  225. X    {
  226. X        *p = 1;
  227. X        delchain_insert(I, *y);
  228. X    }
  229. X    else
  230. X    {
  231. X        /* process parent */
  232. X        nodecopy(I->node, znode);
  233. X        *p = z;
  234. X        *i = zi;
  235. X        I->level--;
  236. X    }
  237. X}
  238. X
  239. X
  240. X/*--------------------------------------------------------------------------*\
  241. X *
  242. X * Function  : move_parentkey
  243. X *
  244. X * Purpose   : 
  245. X *
  246. X * Parameters: I        -
  247. X *               rsib        -
  248. X *               zi        -
  249. X *               z        -
  250. X *               znode    -
  251. X *               y        -
  252. X *               ynode    -
  253. X *
  254. X * Returns   : Nothing.
  255. X *
  256. X */
  257. Xstatic void move_parentkey(I, rsib, zi, z, znode, y, ynode)
  258. XINDEX    *I;
  259. Xix_addr    rsib, y, z;
  260. Xint        zi;
  261. Xchar    *znode, *ynode;
  262. X{
  263. X    if( rsib )
  264. X    {
  265. X        /* copy key from parent to p */
  266. X        keycopy(I->node, NSIZE(I->node), znode, zi);
  267. X
  268. X        /* copy reference of sibling moved to parent */
  269. X        CHILD(I->node, NSIZE(I->node)+1) = CHILD(ynode,0);
  270. X
  271. X        /* copy sibling key to parent */
  272. X        keycopy(znode, zi, ynode, 0);
  273. X        tupledel(ynode, 0);
  274. X    }
  275. X    else
  276. X    {
  277. X        tupleins(I->node, 0, 1);
  278. X
  279. X        /* copy key from parent */
  280. X        keycopy(I->node, 0, znode, zi);
  281. X
  282. X        /* copy reference of sibling moved to parent */
  283. X        CHILD(I->node,0) = CHILD(ynode, NSIZE(ynode));
  284. X
  285. X        /* copy sibling key to parent */
  286. X        keycopy(znode, zi, ynode, NSIZE(ynode)-1);
  287. X    }
  288. X
  289. X    NSIZE(ynode)--;
  290. X    NSIZE(I->node)++;
  291. X
  292. X    nodewrite(I, ynode, y);            /* update nodes                    */
  293. X    nodewrite(I, znode, z);
  294. X}
  295. X
  296. X
  297. X/*--------------------------------------------------------------------------*\
  298. X *
  299. X * Function  : find_ref
  300. X *
  301. X * Purpose   : Find a tuple with a specified reference.
  302. X *
  303. X * Parameters: I        - INDEX handle.
  304. X *               ref        - Reference number.
  305. X *               addr        - Address of node to start search in. If the tuple
  306. X *                          is found, the address of the tuple is returned herein
  307. X *
  308. X * Returns   : S_OKAY    - Reference found.
  309. X *
  310. X */
  311. X
  312. X#define Keys        NSIZE(I->node)
  313. X#define Child(i)    CHILD(I->node, (i))
  314. X#define Key(i)        KEY(I->node, (i))
  315. X#define Ref(i)        REF(I->node, (i))
  316. X#define Pos            (I->path[I->level].i)
  317. X#define Addr        (I->path[I->level].a)
  318. X#define Level        (I->level)
  319. X
  320. X
  321. X
  322. Xstatic find_ref(I, ref, addr, idx, key)
  323. XINDEX    *I;
  324. Xulong    ref;
  325. Xix_addr    *addr;
  326. Xint        *idx;
  327. Xvoid    *key;
  328. X{
  329. X    for( ;; )
  330. X    {
  331. X        *idx  = Pos;
  332. X        *addr = Addr;
  333. X
  334. X        if( (*I->cmpfunc)(key, Key(*idx)) )
  335. X        {
  336. X            puts("key mismatch");
  337. X            break;
  338. X        }
  339. X
  340. X        if( Ref(*idx) == ref )
  341. X            return S_OKAY;
  342. X
  343. X        if( Child(Pos) > 0 )                    /* Non-leaf node            */
  344. X        {
  345. X            /* Get the leftmost child in the left subtree */
  346. X            Pos++;
  347. X            get_leftmostchild(I, Child(Pos));
  348. X        }
  349. X        else if( Pos >= Keys-1 )                /* Leaf node at first pos    */
  350. X        {
  351. X            if( Pos >= Keys-1 && Addr == 1 )
  352. X            {
  353. X                I->curr = 0;
  354. X                RETURN S_NOTFOUND;
  355. X            }
  356. X
  357. X            /* Move upward until a node with Pos<Keys-1 or root is reached    */
  358. X            do
  359. X            {
  360. X                Level--;
  361. X                noderead(I, I->node, Addr);
  362. X            }
  363. X            while( Pos >= Keys && Addr != 1 );
  364. X
  365. X            if( Pos == Keys && Addr == 1 )
  366. X            {
  367. X                I->curr = 0;
  368. X                RETURN S_NOTFOUND;
  369. X            }
  370. X        }
  371. X        else                                    /* Leaf node                */
  372. X            Pos++;
  373. X    }
  374. X    
  375. X    RETURN S_NOTFOUND;
  376. X}
  377. X
  378. X#undef Keys
  379. X#undef Child
  380. X#undef Key
  381. X#undef Ref
  382. X#undef Pos
  383. X#undef Addr
  384. X#undef Level
  385. X
  386. X
  387. X
  388. X
  389. X/*--------------------------------------------------------------------------*\
  390. X *
  391. X * Function  : replace_with_leftmost_tuple
  392. X *
  393. X * Purpose   : Replaces the current tuple [p, I->node, i] with the leftmost
  394. X *               key in the right subtree (of the current tuple).
  395. X *
  396. X * Parameters: I        - Index handle.
  397. X *               y        -
  398. X *               ynode    -
  399. X *               p        - Address of I->node.
  400. X *               i        - Index of I->node.
  401. X *
  402. X * Returns   : 
  403. X *
  404. X */
  405. Xstatic void replace_with_leftmost_tuple(I, y, ynode, p, i)
  406. XINDEX    *I;
  407. Xix_addr    *y;
  408. Xix_addr    *p;
  409. Xchar    *ynode;
  410. Xint        *i;
  411. X{
  412. X    I->path[I->level].i++;
  413. X
  414. X    *y = noderead(I, ynode, CHILD(I->node, *i+1));
  415. X
  416. X    I->path[++I->level].a = CHILD(I->node, *i+1);
  417. X    I->path[  I->level].i = 0;
  418. X
  419. X    while( CHILD(ynode,0) )
  420. X    {
  421. X        *y = noderead(I, ynode, CHILD(ynode, 0));
  422. X
  423. X        I->path[++I->level].a = *y;
  424. X        I->path[  I->level].i = 0;
  425. X    }
  426. X
  427. X    keycopy(I->node, *i, ynode, 0);            /* copy leftmost key to p,i        */
  428. X
  429. X    nodewrite(I, I->node, *p);                /* update node p                */
  430. X    nodecopy(I->node, ynode);
  431. X
  432. X    *p = *y;
  433. X    *i = 0;
  434. X}
  435. X
  436. X
  437. X
  438. X
  439. X/*-------------------------------- btree_del -------------------------------*\
  440. X *
  441. X * Purpose     : Deletes a key in a B-tree. If the deletion causes underflow in
  442. X *               a node, two nodes are merged and the B-tree possibly shrunk.
  443. X *
  444. X * Parameters: I            - B-tree index file descriptor.
  445. X *               key            - Key value to delete.
  446. X *               ref            - Reference of key value. Only used if the B-tree
  447. X *                              contains duplicates.
  448. X *
  449. X * Returns     : S_OKAY        - Key value successfully deleted.
  450. X *               S_NOTFOUND    - The key was not in the B-tree.
  451. X *
  452. X */
  453. Xbtree_del(I, key, ref)
  454. XINDEX *I;
  455. Xvoid *key;
  456. Xulong ref;
  457. X{
  458. X    ix_addr    p, y, z, lsib, rsib;
  459. X    int        i, zi, rc;
  460. X    char    *ynode, *znode;
  461. X
  462. X    I->curr = 0;
  463. X    I->hold = 0;
  464. X
  465. X    btree_getheader(I);
  466. X
  467. X    if( !d_search(I, key, &p, &i) )
  468. X        RETURN S_NOTFOUND;
  469. X
  470. X    if( I->H.dups )
  471. X        if( (rc = find_ref(I, ref, &p, &i, key)) != S_OKAY )
  472. X            return rc;
  473. X
  474. X    /* Allocate temporaty node buffers */
  475. X    if( !(ynode = (char *)malloc(I->H.nodesize + I->tsize)) )
  476. X        RETURN S_NOMEM;
  477. X    if( !(znode = (char *)malloc(I->H.nodesize + I->tsize)) )
  478. X    {
  479. X        free(ynode);
  480. X        RETURN S_NOMEM;
  481. X    }
  482. X
  483. X     /* if node is a nonleaf, replace key with leftmost key in right subtree */
  484. X    if( CHILD(I->node, 0) )
  485. X        replace_with_leftmost_tuple(I, &y, ynode, &p, &i);
  486. X        
  487. X    tupledel(I->node, i);                    /* remove key from leaf            */
  488. X    NSIZE(I->node)--;                        /* decrease node size by 1        */
  489. X
  490. X    /* run loop as long there is underflow in p and p is not root            */
  491. X    while( NSIZE(I->node) < (ulong)I->H.order/2 && p != 1 )
  492. X    {
  493. X        z  = I->path[I->level-1].a;            /* set z = parent                */
  494. X        zi = I->path[I->level-1].i;            /* set zi = parent i            */
  495. X
  496. X        noderead(I,znode,z);                /* read parent node from disk    */
  497. X
  498. X        lsib = zi ? CHILD(znode, zi-1) : 0;
  499. X        rsib = zi < NSIZE(znode) ? CHILD(znode, zi+1) : 0;
  500. X
  501. X        y = rsib ? rsib : lsib;
  502. X
  503. X        noderead(I, ynode, y);
  504. X
  505. X        if( !rsib )
  506. X            zi--;
  507. X
  508. X        if( NSIZE(ynode) > (ulong)I->H.order/2 )
  509. X        {
  510. X            /* move parent key to p, move nearest key in sibling to p */
  511. X            move_parentkey(I, rsib, zi, z, znode, y, ynode);
  512. X        
  513. X            goto out;
  514. X        }
  515. X        else
  516. X        {
  517. X            /* there is underflow in leaf p - merge with a sibling    */
  518. X            merge_siblings(I, lsib, rsib, z, zi, znode, &y, ynode, &p, &i);
  519. X        }
  520. X    }
  521. X
  522. X    I->H.keys--;
  523. X
  524. Xout:
  525. X
  526. X    if( !NSIZE(I->node) )                  /* if index is empty, truncate    */
  527. X    {
  528. X        I->H.first_deleted = 0;
  529. X        I->H.keys = 0;
  530. X#if defined(DOS) || defined(OS2) 
  531. X        chsize(I->fh, 0);
  532. X#else
  533. X#ifdef SCO
  534. X        os_close(os_open(I->fname, O_RDWR|O_TRUNC, CREATMASK));
  535. X#else
  536. X        ftruncate(I->fh, I->H.nodesize);
  537. X#endif
  538. X#endif
  539. X    }
  540. X    else
  541. X        nodewrite(I, I->node, p);              /* else update node p            */
  542. X
  543. X    I->H.timestamp++;
  544. X    btree_putheader(I);
  545. X
  546. X    free(znode);
  547. X    free(ynode);
  548. X
  549. X    RETURN S_OKAY;
  550. X}
  551. X
  552. X/* end-of-file */
  553. END_OF_FILE
  554.   if test 12035 -ne `wc -c <'typhoon/src/bt_del.c'`; then
  555.     echo shar: \"'typhoon/src/bt_del.c'\" unpacked with wrong size!
  556.   fi
  557.   # end of 'typhoon/src/bt_del.c'
  558. fi
  559. if test -f 'typhoon/src/bt_open.c' -a "${1}" != "-c" ; then 
  560.   echo shar: Will not clobber existing file \"'typhoon/src/bt_open.c'\"
  561. else
  562.   echo shar: Extracting \"'typhoon/src/bt_open.c'\" \(11821 characters\)
  563.   sed "s/^X//" >'typhoon/src/bt_open.c' <<'END_OF_FILE'
  564. X/*----------------------------------------------------------------------------
  565. X * File    : bt_open.c
  566. X * Library : typhoon
  567. X * OS      : UNIX, OS/2, DOS
  568. X * Author  : Thomas B. Pedersen
  569. X *
  570. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  571. X *
  572. X * Permission is hereby granted, without written agreement and without
  573. X * license or royalty fees, to use, copy, modify, and distribute this
  574. X * software and its documentation for any purpose, provided that the above
  575. X * copyright notice and the following two  paragraphs appear (1) in all 
  576. X * source copies of this software and (2) in accompanying documentation
  577. X * wherever the programatic interface of this software, or any derivative
  578. X * of it, is described.
  579. X *
  580. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  581. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  582. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  583. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  584. X *
  585. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  586. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  587. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  588. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  589. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  590. X *
  591. X * Description:
  592. X *   Contains functions for opening and closing B-tree index files.
  593. X *
  594. X * Functions:
  595. X *   db_keygetheader    - Read B-tree inde xfile header.
  596. X *   db_keyputheader    - Write B-tree index file header.
  597. X *   d_keyopen            - Open a B-tree index file.
  598. X *   d_keyclose            - Close a B-tree index file.
  599. X *   nodesearch            - Perform binary search in the node.
  600. X *   d_search            - Find a key.
  601. X *
  602. X * $Log: bt_open.c,v $
  603. X * Revision 1.2  1994/09/17  16:00:13  tbp
  604. X * typhoon.h and environ.h are now included from <>.
  605. X *
  606. X * Revision 1.1  1994/09/13  21:28:29  tbp
  607. X * Added to repository.
  608. X * 
  609. X *
  610. X *--------------------------------------------------------------------------*/
  611. X
  612. Xstatic char rcsid[] = "$Id: bt_open.c,v 1.2 1994/09/17 16:00:13 tbp Exp $";
  613. X
  614. X#include <string.h>
  615. X#include <stdio.h>
  616. X#include <fcntl.h>
  617. X#include <errno.h>
  618. X#ifdef UNIX
  619. X#     include <unistd.h>
  620. X#    ifdef __STDC__
  621. X#        include <stdlib.h>
  622. X#    endif
  623. X#else
  624. X#    include <sys/stat.h>
  625. X#    include <stdlib.h>
  626. X#    include <io.h>
  627. X#endif
  628. X#include <typhoon.h>
  629. X#include "ty_dbd.h"
  630. X#include "ty_type.h"
  631. X#include "ty_prot.h"
  632. X#include "ty_glob.h"
  633. X#include "btree.h"
  634. X
  635. X
  636. Xint find_firstoccurrence  PRM( (INDEX *, void *, ix_addr *, int *); )
  637. X
  638. X/*----------------------------- btree_getheader ----------------------------*\
  639. X *
  640. X * Purpose     : Reads the header of a B-tree index file.
  641. X *
  642. X * Parameters: I        - Pointer to index file descriptor.
  643. X *
  644. X * Returns     : Nothing.
  645. X *
  646. X */
  647. X
  648. Xvoid btree_getheader(I)
  649. XINDEX *I;
  650. X{
  651. X    lseek(I->fh, 0L, SEEK_SET);
  652. X    read(I->fh, &I->H, sizeof I->H);
  653. X}
  654. X
  655. X
  656. X/*----------------------------- btree_getheader ----------------------------*\
  657. X *
  658. X * Purpose     : Writes the header of a B-tree index file.
  659. X *
  660. X * Parameters: I        - Pointer to index file descriptor.
  661. X *
  662. X * Returns     : Nothing.
  663. X *
  664. X */
  665. X
  666. Xvoid btree_putheader(I)
  667. XINDEX *I;
  668. X{
  669. X    lseek(I->fh, 0L, SEEK_SET);
  670. X    write(I->fh, &I->H, sizeof I->H);
  671. X}
  672. X
  673. X
  674. X/*-------------------------------- btree_open -------------------------------*\
  675. X *
  676. X * Purpose     : Opens a B-tree index file with the name <fname>. If the file
  677. X *               does not already exist, the file is created. If the version of
  678. X *               the existing file does not match the version of the B-tree
  679. X *               library db_status is set to S_VERSION, and NULL is returned.
  680. X *
  681. X * Parameters: fname        - File name.
  682. X *               keysize        - Key size.
  683. X *               nodesize        - Node size. Multiples of 512 are recommended.
  684. X *               cmpfunc        - Comparison function. This function must take two
  685. X *                              parameters, i.e. like strcmp().
  686. X *               dups            - True if duplicates are allowed.
  687. X *               shared        - Open the index file in shared mode?.
  688. X *
  689. X * Returns     : If the file was successfully opened, a pointer to a B-tree
  690. X *               index file descriptor is returned, otherwise NULL is returned
  691. X *               and db_status is set to one of following:
  692. X *
  693. X *                S_NOMEM        - Out of memory.
  694. X *                S_IOFATAL    - File could not be opened.
  695. X *                S_VERSION    - B-tree file on disk has wrong version.
  696. X *               S_UNAVAIL    - The file is already opened in non-shared mode.
  697. X *
  698. X */
  699. X
  700. XINDEX *btree_open(fname, keysize, nodesize, cmpfunc, dups, shared)
  701. Xchar   *fname;
  702. Xint     keysize, dups, nodesize, shared;
  703. XCMPFUNC cmpfunc;
  704. X{
  705. X    INDEX *I;
  706. X    int tuplesize, isnew, fh;
  707. X    int aligned_keysize;
  708. X
  709. X    /* See if file exists and then open it */
  710. X    isnew = access(fname, 0);
  711. X    if( (fh=os_open(fname, O_BINARY|O_CREAT|O_RDWR,CREATMASK)) == -1 )
  712. X    {
  713. X        db_status = S_IOFATAL;
  714. X        return NULL;
  715. X    }
  716. X
  717. X    /* Lock the file if it is not opened in shared mode */
  718. X    if( !shared )
  719. X        if( os_lock(fh, 0L, 1, 't') == -1 )
  720. X        {
  721. X            db_status = S_NOTAVAIL;
  722. X            return NULL;
  723. X        }
  724. X
  725. X    /* Ensure that the size of a tuple is multiple of four */
  726. X    aligned_keysize = keysize;
  727. X#ifdef RISC
  728. X    if( aligned_keysize & 3 )
  729. X        aligned_keysize += 4 - (aligned_keysize & 3);
  730. X#endif
  731. X
  732. X    /* calculate memory requirements */
  733. X    tuplesize = sizeof(A_type) + sizeof(R_type) + aligned_keysize;
  734. X
  735. X    /* allocate memory for INDEX structure */
  736. X    if( (I = (INDEX *)calloc(sizeof(*I) + nodesize + tuplesize,1)) == NULL )
  737. X    {
  738. X        os_close(fh);
  739. X        db_status = S_NOMEM;
  740. X        return NULL;
  741. X    }
  742. X
  743. X    /* allocate memory for current key */
  744. X    if( (I->curkey = (char *)malloc(keysize)) == NULL )
  745. X    {
  746. X        os_close(fh);
  747. X        free(I);
  748. X        db_status = S_NOMEM;
  749. X        return NULL;
  750. X    }
  751. X
  752. X    I->fh = fh;
  753. X
  754. X    if( isnew )
  755. X    {
  756. X        I->H.version        = KEYVERSION_NUM;
  757. X        I->H.first_deleted  = 0;
  758. X        I->H.order             = ((nodesize-sizeof(N_type)-sizeof(A_type)) / tuplesize) & 0xfffe;
  759. X        I->H.keysize        = keysize;
  760. X        I->H.dups           = dups;
  761. X        I->H.nodesize       = nodesize;
  762. X        I->H.keys            = 0;
  763. X        strcpy(I->H.id, KEYVERSION_ID);
  764. X        memset(I->H.spare, 0, sizeof I->H.spare);
  765. X        btree_putheader(I);
  766. X    }
  767. X    else
  768. X    {
  769. X        btree_getheader(I);
  770. X
  771. X        if( I->H.version != KEYVERSION_NUM )
  772. X        {
  773. X            db_status = S_VERSION;
  774. X            os_close(fh);
  775. X            free(I->curkey);
  776. X            free(I);
  777. X            return NULL;
  778. X        }
  779. X    }
  780. X
  781. X    I->cmpfunc          = cmpfunc;
  782. X    I->tsize            = tuplesize;
  783. X    I->hold                = 0;
  784. X    I->shared            = shared;
  785. X    I->aligned_keysize    = aligned_keysize;
  786. X    strcpy(I->fname, fname);
  787. X
  788. X    db_status = S_OKAY;
  789. X
  790. X    return I;
  791. X}
  792. X
  793. X
  794. X/*-------------------------------- btree_close ------------------------------*\
  795. X *
  796. X * Purpose     : Closes a B-tree index file previously opened with d_keyopen().
  797. X *               All nodes that might be in the cache are written to disk.
  798. X *
  799. X * Parameters: I    - Index file descriptor.
  800. X *
  801. X * Returns     : Nothing.
  802. X *
  803. X */
  804. Xvoid btree_close(I)
  805. XINDEX *I;
  806. X{
  807. X    int i;
  808. X
  809. X    if( I->fh != -1 )
  810. X    {
  811. X        btree_putheader(I);
  812. X           os_close(I->fh);
  813. X    }
  814. X
  815. X    free(I->curkey);
  816. X    free(I);
  817. X}
  818. X
  819. X
  820. Xbtree_dynclose(I)
  821. XINDEX *I;
  822. X{
  823. X    if( I->fh != -1 )
  824. X    {
  825. X        close(I->fh);
  826. X        I->fh = -1;
  827. X    }
  828. X
  829. X    RETURN S_OKAY;
  830. X}
  831. X
  832. X
  833. Xbtree_dynopen(I)
  834. XINDEX *I;
  835. X{
  836. X    if( I->fh == -1 )
  837. X        if( (I->fh=os_open(I->fname, O_BINARY|O_CREAT|O_RDWR,CREATMASK)) == -1 )
  838. X            RETURN S_IOFATAL;
  839. X
  840. X    RETURN S_OKAY;
  841. X}
  842. X
  843. X
  844. X/*------------------------------- nodesearch -------------------------------*\
  845. X *
  846. X * Purpose     : Performs a binary search for the key value pointed to by <key>
  847. X *               in the node in I. When the function returned <i> contains the
  848. X *               entry in the node where the searched stopped. If the key was
  849. X *               found REF(i) contains the reference to be returned by the
  850. X *               calling, otherwise CHILD(i) contains the node address of the
  851. X *               child to be processed next.
  852. X *
  853. X * Parameters: I        - B-tree index file descriptor.
  854. X *               key        - Key value being searched for.
  855. X *               i        - Contains node index when function returns.
  856. X *
  857. X * Returns     : 0        - The key was found.
  858. X *               not 0    - The key was not found.
  859. X *
  860. X */
  861. Xnodesearch(I, key, i)
  862. XINDEX *I;
  863. Xvoid  *key;
  864. Xint   *i;
  865. X{
  866. X    int cmp, mid, upr, lwr;
  867. X
  868. X    upr = NSIZE(I->node) - 1;
  869. X    lwr = 0;
  870. X
  871. X    /* Perform binary search in node */
  872. X    while( lwr <= upr )
  873. X    {
  874. X        mid = (lwr + upr) >> 1;
  875. X        cmp = (*I->cmpfunc)(key, KEY(I->node, mid));
  876. X
  877. X        if( cmp > 0 )
  878. X            lwr = mid + 1;
  879. X        else if( cmp < 0 )
  880. X            upr = mid - 1;
  881. X        else
  882. X        {
  883. X            if( I->H.dups )
  884. X            {
  885. X                /* Find the leftmost occurrence */
  886. X                while( mid > 0 )
  887. X                {
  888. X                    mid--;
  889. X                    if( cmp = (*I->cmpfunc)(key, KEY(I->node, mid)) )
  890. X                        break;
  891. X                }
  892. X                if( cmp )
  893. X                     mid++;
  894. X
  895. X                *i = mid;
  896. X                return 0;
  897. X            }
  898. X            break;
  899. X        }
  900. X    }
  901. X
  902. X    /* If the comparison yielded greater than, move a step to the right */
  903. X    if( cmp > 0 )
  904. X        mid++;
  905. X
  906. X    *i = mid;
  907. X    return cmp;
  908. X}
  909. X
  910. X
  911. X/*-------------------------------- d_search --------------------------------*\
  912. X *
  913. X * Purpose     : Searches a B-tree for the key value pointed to by <key>. If
  914. X *               the key is found the reference is in REF(i). The path from the
  915. X *               root to the last access node is stored in I->path[], which
  916. X *               enables key traversal from the current point in the tree.
  917. X *
  918. X *               The search starts at the root, which is always at address 1. For
  919. X *               each node nodesearch is called to perform a binary search in the
  920. X *               node. If the key is not found, the search ends in a leaf node.
  921. X *
  922. X *               If duplicates are allowed, the first occurrence of the key
  923. X *               value must be found.
  924. X *
  925. X * Parameters: I        - B-tree index file descriptor.
  926. X *               key        - Key value being searched for.
  927. X *               addr        - Contains node address when function returns.
  928. X *               i        - Contains node index when function returns.
  929. X *
  930. X * Returns     : 0        - The key was found.
  931. X *               1        - The key was not found.
  932. X *
  933. X */
  934. Xd_search(I, key, addr, i)
  935. XINDEX     *I;
  936. Xvoid      *key;
  937. Xix_addr   *addr;
  938. Xint       *i;
  939. X{
  940. X    int cmp;
  941. X
  942. X    /* Start the search at the root */
  943. X    *addr = 1;
  944. X    *i = 0;
  945. X    I->level = 0;
  946. X
  947. X
  948. X    for( ;; )
  949. X    {
  950. X        /* Save the addresses and indexes of the traversed nodes */
  951. X        I->path[++I->level].a = *addr;
  952. X
  953. X        if( noderead(I, I->node, *addr) == (ix_addr)-1 )
  954. X        {
  955. X            /* The node could not be read - zero the number of keys */
  956. X            NSIZE(I->node) = 0;
  957. X            return 0;
  958. X        }
  959. X
  960. X        cmp = nodesearch(I,key,i);
  961. X
  962. X        I->path[I->level].i = *i;
  963. X
  964. X        if( !cmp )
  965. X        {
  966. X            if( I->H.dups )
  967. X                return find_firstoccurrence(I, key, addr, i);
  968. X            return 1;
  969. X        }
  970. X
  971. X        if( CHILD(I->node, *i) )
  972. X            *addr = CHILD(I->node, *i);
  973. X        else
  974. X            return 0;
  975. X    }
  976. X}
  977. X
  978. X
  979. X/*-------------------------- find_firstoccurrence --------------------------*\
  980. X *
  981. X * Purpose     : This function is called in order to find the first occurrence
  982. X *               of a duplicate key in a non-unique index.
  983. X *
  984. X * Parameters: I        - B-tree index file descriptor.
  985. X *               key        - Key value being searched for.
  986. X *               addr        - Contains node address when function returns.
  987. X *               i        - Contains node index when function returns.
  988. X *
  989. X * Returns     : 0        - The key was found.
  990. X *               1        - The key was not found.
  991. X *
  992. X */
  993. Xfind_firstoccurrence(I, key, addr, i)
  994. XINDEX     *I;
  995. Xvoid      *key;
  996. Xix_addr   *addr;
  997. Xint       *i;
  998. X{
  999. X    int first_occurlevel = I->level;
  1000. X    int cmp = 0;
  1001. X
  1002. X    while( CHILD(I->node, 0) )
  1003. X    {
  1004. X        I->level++;
  1005. X        I->path[I->level].a = CHILD(I->node, *i);
  1006. X        I->path[I->level].i = *i;
  1007. X
  1008. X        noderead(I, I->node, I->path[I->level].a);
  1009. X
  1010. X        cmp = nodesearch(I,key,i);
  1011. X
  1012. X        I->path[I->level].i = *i;
  1013. X
  1014. X        /* If the key was found in the current node we search the left
  1015. X         * subtree of the key. Otherwise, we search the right subtree of
  1016. X         * the rightmost key.
  1017. X         */
  1018. X
  1019. X        if( !cmp )
  1020. X            first_occurlevel = I->level;
  1021. X        else
  1022. X            *i = NSIZE(I->node);
  1023. X    }
  1024. X
  1025. X    if( cmp )
  1026. X    {
  1027. X        I->level = first_occurlevel;
  1028. X        *i       = I->path[I->level].i;
  1029. X        *addr     = I->path[I->level].a;
  1030. X
  1031. X        noderead(I, I->node, I->path[I->level].a);
  1032. X    }
  1033. X    else
  1034. X    {
  1035. X        *i       = I->path[I->level].i;
  1036. X        *addr     = I->path[I->level].a;
  1037. X    }
  1038. X
  1039. X    return 1;
  1040. X}
  1041. X
  1042. X/* end-of-file */
  1043. X
  1044. END_OF_FILE
  1045.   if test 11821 -ne `wc -c <'typhoon/src/bt_open.c'`; then
  1046.     echo shar: \"'typhoon/src/bt_open.c'\" unpacked with wrong size!
  1047.   fi
  1048.   # end of 'typhoon/src/bt_open.c'
  1049. fi
  1050. if test -f 'typhoon/src/ty_ins.c' -a "${1}" != "-c" ; then 
  1051.   echo shar: Will not clobber existing file \"'typhoon/src/ty_ins.c'\"
  1052. else
  1053.   echo shar: Extracting \"'typhoon/src/ty_ins.c'\" \(12105 characters\)
  1054.   sed "s/^X//" >'typhoon/src/ty_ins.c' <<'END_OF_FILE'
  1055. X/*----------------------------------------------------------------------------
  1056. X * File    : ty_ins.c
  1057. X * Library : typhoon
  1058. X * OS      : UNIX, OS/2, DOS
  1059. X * Author  : Thomas B. Pedersen
  1060. X *
  1061. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  1062. X *
  1063. X * Permission is hereby granted, without written agreement and without
  1064. X * license or royalty fees, to use, copy, modify, and distribute this
  1065. X * software and its documentation for any purpose, provided that the above
  1066. X * copyright notice and the following two  paragraphs appear (1) in all 
  1067. X * source copies of this software and (2) in accompanying documentation
  1068. X * wherever the programatic interface of this software, or any derivative
  1069. X * of it, is described.
  1070. X *
  1071. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  1072. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  1073. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  1074. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1075. X *
  1076. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  1077. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  1078. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  1079. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  1080. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  1081. X *
  1082. X * Description:
  1083. X *   Contains API functions.
  1084. X *
  1085. X * Functions:
  1086. X *   report_err           - Report an error to the user.
  1087. X *   d_keyread           - Read the value of the last retrieved key.
  1088. X *   d_keyfind           - Find a key.
  1089. X *   d_keymove           - Perform a d_keyfrst(), d_keylast(), d_keyprev() or
  1090. X *                         d_keynext().
  1091. X *   d_recmove           - Perform a d_recfrst(), d_reclast(), d_recprev() or
  1092. X *                         d_recnext().
  1093. X *   d_crread           - Read the value of a field of the current record.
  1094. X *   d_recwrite        - Update a record.
  1095. X *   d_recread        - Read the current record.
  1096. X *   d_fillnew        - Add a new record to the database.
  1097. X *   d_delete        - Delete the current record.
  1098. X *   d_crget        - Get the database address of the current record.
  1099. X *   d_crset        - Set the database address of the current record.
  1100. X *   d_records        - Return the number of records in a file.
  1101. X *   d_getkeysize    - Return the size of a key.
  1102. X *   d_getrecsize    - Return the size of a record.
  1103. X *
  1104. X * $Log: ty_ins.c,v $
  1105. X * Revision 1.2  1994/09/17  16:00:16  tbp
  1106. X * typhoon.h and environ.h are now included from <>.
  1107. X *
  1108. X * Revision 1.1  1994/09/13  21:28:34  tbp
  1109. X * Added to repository.
  1110. X * 
  1111. X *
  1112. X *--------------------------------------------------------------------------*/
  1113. X
  1114. Xstatic char rcsid[] = "$Id: ty_ins.c,v 1.2 1994/09/17 16:00:16 tbp Exp $";
  1115. X
  1116. X#ifdef UNIX
  1117. X#    include <unistd.h>
  1118. X#endif
  1119. X#include <string.h>
  1120. X#include <stdio.h>
  1121. X#include <typhoon.h>
  1122. X#include "ty_dbd.h"
  1123. X#include "ty_type.h"
  1124. X#define DEFINE_GLOBALS
  1125. X#include "ty_glob.h"
  1126. X#include "ty_prot.h"
  1127. X
  1128. X
  1129. Xreport_err(v)
  1130. Xint v;
  1131. X{
  1132. X    if( typhoon.ty_errfn )
  1133. X        typhoon.ty_errfn(db_status, db_subcode);
  1134. X    else
  1135. X    {
  1136. X#ifdef UNIX
  1137. X        printf("** pid %d - db_status = %d **\n", getpid(), db_status = v);
  1138. X#endif
  1139. X#ifdef OS2
  1140. X        printf("** db_status = %d **\n", db_status = v);
  1141. X#endif
  1142. X    }
  1143. X
  1144. X    return v;
  1145. X}
  1146. X
  1147. X
  1148. X
  1149. X/*--------------------------------- d_block ---------------------------------*\
  1150. X *
  1151. X * Purpose     : Requests exclusive access to the API. The second time another
  1152. X *             thread in a program calls this function it will block, until
  1153. X *             d_unblock() is called.
  1154. X *
  1155. X * Parameters: None.
  1156. X *
  1157. X * Returns     : S_OKAY    - Ok.
  1158. X *
  1159. X */
  1160. X
  1161. XFNCLASS d_block()
  1162. X{
  1163. X#ifdef OS2
  1164. X    os2_block();
  1165. X#endif
  1166. X
  1167. X    RETURN S_OKAY;
  1168. X}
  1169. X
  1170. X
  1171. X
  1172. XFNCLASS d_unblock()
  1173. X{
  1174. X#ifdef OS2
  1175. X    os2_unblock();
  1176. X#endif
  1177. X
  1178. X    RETURN S_OKAY;
  1179. X}
  1180. X
  1181. X
  1182. X/*------------------------------- d_recwrite -------------------------------*\
  1183. X *
  1184. X * Purpose     : Updates the contents of the current record.
  1185. X *
  1186. X * Parameters: buf            - Buffer containing current record.
  1187. X *
  1188. X * Returns     : S_OKAY        - Operation performed successfully.
  1189. X *               S_DUPLICATE    - The record contained a duplicate key. db_subcode
  1190. X *                              contains the id of the conflicting field or key.
  1191. X *               S_NOCD        - No current database.
  1192. X *               S_NOCR        - No current record.
  1193. X *             S_RECSIZE    - Invalid record size (if variable size). 
  1194. X *                              db_subcode contains the ID of the size field.
  1195. X *               S_FOREIGN    - A foreign key was not found (db_subcode holds
  1196. X *                              the foreing key ID).
  1197. X *               S_RESTRICT    - The primary key was updated, but a dependent
  1198. X *                              table with restrict rule had a record which 
  1199. X *                              referenced the record to be deleted. 
  1200. X *                              (db_subcode holds the foreign key ID).
  1201. X *
  1202. X */
  1203. XFNCLASS d_recwrite(buf)
  1204. Xvoid *buf;
  1205. X{
  1206. X    Record *rec;
  1207. X    Key *key;
  1208. X    Key *keyptr[RECKEYS_MAX];
  1209. X    int keys_changed=0, rc;
  1210. X    int i, n;
  1211. X    ulong ref;
  1212. X
  1213. X    /* Set pointers to current record and first field */
  1214. X    if( (rc = set_recfld(-1, &rec, NULL)) != S_OKAY )
  1215. X           return rc;
  1216. X
  1217. X    ty_lock();
  1218. X    if( (rc = update_recbuf()) != S_OKAY )
  1219. X    {
  1220. X        ty_unlock();
  1221. X        return rc;
  1222. X    }
  1223. X
  1224. X    /* Check foreign keys (if any) */
  1225. X    if( (rc = check_foreign_keys(rec, buf, 0)) != S_OKAY )
  1226. X    {
  1227. X        ty_unlock();
  1228. X        return rc;
  1229. X    }
  1230. X
  1231. X    /* Check dependent tables (if any) */
  1232. X    if( (rc = check_dependent_tables(rec, buf, 'u')) != S_OKAY )
  1233. X    {
  1234. X        ty_unlock();
  1235. X        return rc;
  1236. X    }
  1237. X
  1238. X    /* Have any keys changed? */
  1239. X    key = DB->key + rec->first_key;
  1240. X
  1241. X    /* Find out which keys have changed and must be updated. An optional key
  1242. X     * that has changed from null to not null, or not null to null, or 
  1243. X     * has changed its value is regarded as changed.
  1244. X     */
  1245. X
  1246. X    for( n = rec->keys; n-- && KT_GETBASIC(key->type) != KT_FOREIGN; key++ )
  1247. X    {
  1248. X        if( reckeycmp(key, buf, DB->recbuf) )
  1249. X        {
  1250. X            keyptr[keys_changed++] = key;
  1251. X
  1252. X            if( key->type & KT_UNIQUE )
  1253. X            {
  1254. X                if( (key->type & KT_OPTIONAL) && null_indicator(key, buf) )
  1255. X                    continue;
  1256. X            
  1257. X                if( keyfind(key, buf, &ref) == S_OKAY )
  1258. X                {
  1259. X                    set_subcode(key);
  1260. X                    ty_unlock();
  1261. X                    RETURN S_DUPLICATE;
  1262. X                }
  1263. X            }
  1264. X        }
  1265. X    }
  1266. X
  1267. X    for( n=0; n<keys_changed; n++ )
  1268. X    {
  1269. X        key = keyptr[n];
  1270. X
  1271. X        if( reckeycmp(key, buf, DB->recbuf) )
  1272. X        {
  1273. X            /* Don't remove null keys */
  1274. X            if( !(key->type & KT_OPTIONAL) || !null_indicator(key, DB->recbuf) )
  1275. X                keydel(key, DB->recbuf, CURR_REC);
  1276. X
  1277. X            /* Don't insert null keys */
  1278. X            if( (key->type & KT_OPTIONAL) && null_indicator(key, buf) )
  1279. X                continue;
  1280. X
  1281. X            if( (rc = keyadd(key, buf, CURR_REC)) != S_OKAY )
  1282. X            {
  1283. X                set_subcode(key);
  1284. X                ty_unlock();
  1285. X                RETURN rc;
  1286. X            }
  1287. X        }
  1288. X    }
  1289. X
  1290. X    if( rec->is_vlr )
  1291. X    {
  1292. X        unsigned size;
  1293. X    
  1294. X        if( (rc = compress_vlr(COMPRESS, rec, DB->recbuf, buf, &size)) != S_OKAY )
  1295. X        {
  1296. X            ty_unlock();
  1297. X            return rc;
  1298. X        }
  1299. X
  1300. X        ty_vlrwrite(rec, DB->real_recbuf, size, CURR_REC);
  1301. X    }
  1302. X    else
  1303. X    {
  1304. X        memcpy(DB->recbuf, buf, rec->size);
  1305. X
  1306. X        ty_recwrite(rec, DB->real_recbuf, CURR_REC);
  1307. X    }
  1308. X
  1309. X    /* Store changed references to parent records */
  1310. X    update_foreign_keys(rec, 0);
  1311. X
  1312. X    if( DB->logging )
  1313. X        ty_log('u');
  1314. X
  1315. X    log_update(CURR_RECID, CURR_REC, rec->size, buf);
  1316. X
  1317. X    ty_unlock();
  1318. X
  1319. X    RETURN S_OKAY;
  1320. X}
  1321. X
  1322. X
  1323. X
  1324. X/*-------------------------------- d_recread -------------------------------*\
  1325. X *
  1326. X * Purpose     : Read contents of the current record.
  1327. X *
  1328. X * Parameters: buf            - Buffer containing current record.
  1329. X *
  1330. X * Returns     : S_OKAY        - Operation performed successfully.
  1331. X *               S_DELETED    - Record has been deleted since last accessed.
  1332. X *               S_NOCD        - No current database.
  1333. X *               S_NOCR        - No current record.
  1334. X *
  1335. X */
  1336. X
  1337. XFNCLASS d_recread(buf)
  1338. Xvoid *buf;
  1339. X{
  1340. X    Record *rec;
  1341. X    int rc;
  1342. X
  1343. X    if( CURR_DB == -1 )
  1344. X        RETURN_RAP(S_NOCD);
  1345. X
  1346. X    if( CURR_REC == 0 )
  1347. X        RETURN_RAP(S_NOCR);
  1348. X
  1349. X    ty_lock();
  1350. X    rec = DB->record + CURR_RECID;
  1351. X
  1352. X    if( (rc = update_recbuf()) != S_OKAY )
  1353. X    {
  1354. X        ty_unlock();
  1355. X        return rc;
  1356. X    }
  1357. X    
  1358. X    if( rec->is_vlr )
  1359. X        rc = compress_vlr(UNCOMPRESS, rec, buf, DB->recbuf, NULL);
  1360. X    else
  1361. X    {
  1362. X        memcpy(buf, DB->recbuf, rec->size);
  1363. X        rc = S_OKAY;
  1364. X    }
  1365. X
  1366. X    ty_unlock();
  1367. X
  1368. X    RETURN rc;
  1369. X}
  1370. X
  1371. X
  1372. X
  1373. X/*------------------------------- d_fillnew --------------------------------*\
  1374. X *
  1375. X * Purpose     : Adds a new record to the current database and updates indexes.
  1376. X *
  1377. X * Parameters: record        - Record id.
  1378. X *               buf            - Pointer to record buffer.
  1379. X *
  1380. X * Returns     : S_OKAY        - Ok.
  1381. X *               S_NOCD        - No current database.
  1382. X *               S_INVREC     - Invalid record id.
  1383. X *             S_DUPLICATE  - The record contained a duplicate key. The id
  1384. X *                            of the field or compound key is stored in
  1385. X *                            db_subcode.
  1386. X *             S_RECSIZE    - Invalid record size (if variable size). 
  1387. X *                              db_subcode contains the ID of the size field.
  1388. X *               S_FOREIGN    - A foreign key was not found (db_subcode holds
  1389. X *                              the foreing key ID.
  1390. X *
  1391. X */
  1392. X
  1393. XFNCLASS d_fillnew(record, buf)
  1394. XId record;
  1395. Xvoid *buf;
  1396. X{
  1397. X    Record *rec;
  1398. X    Field *fld;
  1399. X    Key *key;
  1400. X    ulong ref;
  1401. X    int i, rc, n;
  1402. X
  1403. X    if( (rc = set_recfld(record, &rec, &fld)) != S_OKAY )
  1404. X        return rc;
  1405. X
  1406. X    /* So far we have no current record */
  1407. X    CURR_REC = 0;
  1408. X
  1409. X    ty_lock();
  1410. X
  1411. X    /* Set pointer to actual data */
  1412. X    DB->recbuf = DB->real_recbuf + rec->preamble;
  1413. X
  1414. X    /* Check foreign keys (if any) */
  1415. X    if( (rc = check_foreign_keys(rec, buf, 1)) != S_OKAY )
  1416. X    {
  1417. X        ty_unlock();
  1418. X        return rc;
  1419. X    }
  1420. X
  1421. X    /* Make sure that there are no duplicate keys in this record */
  1422. X    key = DB->key + rec->first_key;
  1423. X
  1424. X    for( n = rec->keys; n-- && !KEY_ISFOREIGN(key); key++ )
  1425. X    {
  1426. X        if( key->type & KT_UNIQUE )
  1427. X        {
  1428. X            if( KEY_ISOPTIONAL(key) && null_indicator(key, buf) )
  1429. X                continue;
  1430. X
  1431. X            if( keyfind(key, buf, &ref) == S_OKAY )
  1432. X            {
  1433. X                set_subcode(key);
  1434. X                ty_unlock();
  1435. X                RETURN S_DUPLICATE;
  1436. X            }
  1437. X        }
  1438. X    }
  1439. X
  1440. X    /* Update data and index files */
  1441. X    if( rec->is_vlr )
  1442. X    {
  1443. X        unsigned size;
  1444. X    
  1445. X        if( (rc = compress_vlr(COMPRESS, rec, DB->recbuf, buf, &size)) != S_OKAY )
  1446. X        {
  1447. X            ty_unlock();
  1448. X            return rc;
  1449. X        }
  1450. X
  1451. X        if( (rc = ty_vlradd(rec, DB->real_recbuf, size, &CURR_REC)) != S_OKAY )
  1452. X        {
  1453. X            ty_unlock();
  1454. X            return rc;
  1455. X        }
  1456. X
  1457. X        /* The record in DB->recbuf is still compressed */
  1458. X    }
  1459. X    else
  1460. X    {
  1461. X        memcpy(DB->recbuf, buf, rec->size);
  1462. X        if( (rc=ty_recadd(rec, DB->real_recbuf, &CURR_REC)) != S_OKAY )
  1463. X        {
  1464. X            ty_unlock();
  1465. X            return rc;
  1466. X        }
  1467. X    }
  1468. X
  1469. X    CURR_RECID    = rec - DB->record;
  1470. X    n            = rec->keys;
  1471. X    key         = DB->key + rec->first_key;
  1472. X
  1473. X    for( n=rec->keys; n-- && !KEY_ISFOREIGN(key); key++ )
  1474. X    {
  1475. X        /* Don't store null keys */
  1476. X        if( KEY_ISOPTIONAL(key) && null_indicator(key, buf) )
  1477. X            continue;
  1478. X
  1479. X        if( (rc = keyadd(key, buf, CURR_REC)) != S_OKAY )
  1480. X        {
  1481. X            ty_unlock();
  1482. X            RETURN rc;
  1483. X        }
  1484. X    }
  1485. X
  1486. X    /* Store references to parent records */
  1487. X    update_foreign_keys(rec, 1);
  1488. X
  1489. X    if( DB->logging )
  1490. X        ty_log('u');
  1491. X
  1492. X    log_update(CURR_RECID, CURR_REC, rec->size, buf);
  1493. X
  1494. X    ty_unlock();
  1495. X
  1496. X    RETURN S_OKAY;
  1497. X}
  1498. X
  1499. X
  1500. X/*-------------------------------- d_delete --------------------------------*\
  1501. X *
  1502. X * Purpose     : Delete the current record.
  1503. X *
  1504. X * Parameters: None.
  1505. X *
  1506. X * Returns     : S_OKAY        - The was successfully deleted.
  1507. X *               S_NOCD        - No current database.
  1508. X *               S_NOCR        - No current record.
  1509. X *               S_RESTRICT    - A dependent table had a foreign key which
  1510. X *                              referenced the primary key of the record to
  1511. X *                              to be deleted. db_subcode holds the foreign
  1512. X *                              key ID.
  1513. X *
  1514. X */
  1515. X
  1516. XFNCLASS d_delete()
  1517. X{
  1518. X    Record *rec;
  1519. X    Key *key;
  1520. X    int n, rc;
  1521. X
  1522. X    if( CURR_DB == -1 )
  1523. X        RETURN_RAP(S_NOCD);
  1524. X
  1525. X    if( CURR_REC == 0 )
  1526. X        RETURN_RAP(S_NOCR);
  1527. X
  1528. X    /* We must update recbuf in order to access the record's keys */
  1529. X    ty_lock();
  1530. X
  1531. X    rec = DB->record + CURR_RECID;
  1532. X    DB->recbuf = DB->real_recbuf + rec->preamble;
  1533. X
  1534. X    if( (rc = update_recbuf()) != S_OKAY )
  1535. X    {
  1536. X        ty_unlock();
  1537. X        return rc;
  1538. X    }
  1539. X
  1540. X    /* Check dependent tables (if any) */
  1541. X    if( (rc = check_dependent_tables(rec, DB->recbuf, 'd')) != S_OKAY )
  1542. X    {
  1543. X        ty_unlock();
  1544. X        return rc;
  1545. X    }
  1546. X
  1547. X    key = DB->key + rec->first_key;
  1548. X
  1549. X    if( DB->fh[rec->fileid].any->type == 'd' )
  1550. X        rc = ty_recdelete(rec, CURR_REC);
  1551. X    else
  1552. X        rc = ty_vlrdel(rec, CURR_REC);
  1553. X
  1554. X    if( rc != S_OKAY )
  1555. X    {
  1556. X        ty_unlock();
  1557. X        RETURN rc;
  1558. X    }
  1559. X
  1560. X    for( n=rec->keys; n-- && !KEY_ISFOREIGN(key); key++ )
  1561. X    {
  1562. X        if( KEY_ISOPTIONAL(key) && null_indicator(key, DB->recbuf) )
  1563. X            continue;
  1564. X    
  1565. X        if( (rc = keydel(key, DB->recbuf, CURR_REC)) != S_OKAY )
  1566. X        {
  1567. X            printf("typhoon: could not delete key %s.%s (db_status %d)\n",
  1568. X                rec->name, key->name, rc);
  1569. X            ty_unlock();
  1570. X            RETURN rc;
  1571. X        }
  1572. X    }
  1573. X
  1574. X    delete_foreign_keys(rec);
  1575. X
  1576. X    if( DB->logging )
  1577. X        ty_log('d');
  1578. X
  1579. X    log_delete(CURR_RECID, CURR_REC);
  1580. X
  1581. X    CURR_REC = 0;
  1582. X
  1583. X    ty_unlock();
  1584. X
  1585. X    RETURN S_OKAY;
  1586. X}
  1587. X
  1588. X/* end-of-file */
  1589. END_OF_FILE
  1590.   if test 12105 -ne `wc -c <'typhoon/src/ty_ins.c'`; then
  1591.     echo shar: \"'typhoon/src/ty_ins.c'\" unpacked with wrong size!
  1592.   fi
  1593.   # end of 'typhoon/src/ty_ins.c'
  1594. fi
  1595. if test -f 'typhoon/src/ty_io.c' -a "${1}" != "-c" ; then 
  1596.   echo shar: Will not clobber existing file \"'typhoon/src/ty_io.c'\"
  1597. else
  1598.   echo shar: Extracting \"'typhoon/src/ty_io.c'\" \(12101 characters\)
  1599.   sed "s/^X//" >'typhoon/src/ty_io.c' <<'END_OF_FILE'
  1600. X/*----------------------------------------------------------------------------
  1601. X * File    : bt_io
  1602. X * Library : typhoon
  1603. X * OS      : UNIX, OS/2, DOS
  1604. X * Author  : Thomas B. Pedersen
  1605. X *
  1606. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  1607. X *
  1608. X * Permission is hereby granted, without written agreement and without
  1609. X * license or royalty fees, to use, copy, modify, and distribute this
  1610. X * software and its documentation for any purpose, provided that the above
  1611. X * copyright notice and the following two  paragraphs appear (1) in all 
  1612. X * source copies of this software and (2) in accompanying documentation
  1613. X * wherever the programatic interface of this software, or any derivative
  1614. X * of it, is described.
  1615. X *
  1616. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  1617. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  1618. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  1619. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1620. X *
  1621. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  1622. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  1623. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  1624. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  1625. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  1626. X *
  1627. X * Description:
  1628. X *   This file contains the layer between the low-level B-tree and record
  1629. X *   routines and the Typhoon API functions. The low-level routines are never
  1630. X *   called directly from the API functions.
  1631. X *
  1632. X * +-----------------------------+
  1633. X * |    Typhoon API functions    |
  1634. X * +-----------------------------+
  1635. X * |  Dynamic open files layer   |     <----- this layer
  1636. X * +----------+------------------+
  1637. X * |  B-tree  |  Record  |  VLR  |
  1638. X * +----------+------------------+
  1639. X * |   C language read/write     |
  1640. X * +-----------------------------+
  1641. X *
  1642. X * Functions:
  1643. X *
  1644. X * $Log: ty_io.c,v $
  1645. X * Revision 1.2  1994/09/17  16:00:16  tbp
  1646. X * typhoon.h and environ.h are now included from <>.
  1647. X *
  1648. X * Revision 1.1  1994/09/13  21:28:34  tbp
  1649. X * Added to repository.
  1650. X * 
  1651. X *
  1652. X *--------------------------------------------------------------------------*/
  1653. X
  1654. Xstatic char rcsid[] = "$Id: ty_io.c,v 1.2 1994/09/17 16:00:16 tbp Exp $";
  1655. X
  1656. X#ifdef UNIX
  1657. X#    include <unistd.h>
  1658. X#endif
  1659. X#include <string.h>
  1660. X#include <stdio.h>
  1661. X#include <errno.h>
  1662. X#include <stdarg.h>
  1663. X#include <time.h>
  1664. X#include <typhoon.h>
  1665. X#include "ty_dbd.h"
  1666. X#include "ty_type.h"
  1667. X#include "ty_glob.h"
  1668. X#include "ty_prot.h"
  1669. X
  1670. X#define PTRTORECID(rec)        ((((rec) - DB->record)+1) * REC_FACTOR)
  1671. X
  1672. X/*-------------------------- Function prototypes ---------------------------*/
  1673. Xstatic int    checkfile                PRM( (int); )
  1674. X
  1675. X/*---------------------------- Global variables ----------------------------*/
  1676. Xstatic ulong seqno = 1;                /* Current sequence number (always > 0)    */
  1677. X
  1678. X
  1679. X
  1680. X
  1681. Xty_closeafile()
  1682. X{
  1683. X    ulong lowest_seqno = seqno;
  1684. X    int            dbs, fhs;            /* Used for scanning tables                */
  1685. X    Dbentry        *db =typhoon.dbtab;    /* Used for scanning tables                */
  1686. X    Fh            *fh;                /* Used for scanning tables                */
  1687. X    Fh            *foundfh = NULL;    /* The filehandle found to be closed    */
  1688. X
  1689. X    /* Find the file least recently accessed open file */
  1690. X    dbs = DB_MAX;
  1691. X    while( dbs-- )
  1692. X    {
  1693. X        if( DB->clients )
  1694. X        {
  1695. X            fh    = DB->fh;
  1696. X            fhs    = DB->header.files;
  1697. X
  1698. X            while( fhs-- )
  1699. X            {
  1700. X                if( fh->any && fh->any->fh != -1 )
  1701. X                {
  1702. X                    if( lowest_seqno > fh->any->seqno )
  1703. X                    {
  1704. X                        lowest_seqno = fh->any->seqno;
  1705. X                        foundfh         = fh;
  1706. X                    }
  1707. X                }
  1708. X                fh++;
  1709. X            }    
  1710. X        }
  1711. X        db++;
  1712. X    }
  1713. X
  1714. X    if( foundfh == NULL )
  1715. X    {
  1716. X        printf("\a*** Could not close a file **");
  1717. X        return -1;
  1718. X    }
  1719. X
  1720. X    /* If the file is already closed, we just return */
  1721. X    if( foundfh->any->fh == -1 )
  1722. X        return S_OKAY;
  1723. X
  1724. X    switch( foundfh->any->type )
  1725. X    {
  1726. X        case 'k':
  1727. X        case 'r':
  1728. X            btree_dynclose(foundfh->key); 
  1729. X            break;
  1730. X        case 'd': 
  1731. X            rec_dynclose(foundfh->rec);    
  1732. X            break;
  1733. X        case 'v': 
  1734. X            vlr_dynclose(foundfh->vlr);    
  1735. X            break;
  1736. X    }
  1737. X
  1738. X    /* Mark the file as closed */
  1739. X    typhoon.cur_open--;
  1740. X
  1741. X      return 0;
  1742. X}
  1743. X
  1744. X
  1745. X
  1746. X
  1747. Xstatic checkfile(fileid)
  1748. Xint fileid;
  1749. X{
  1750. X    Fh *fh;
  1751. X    int rc;
  1752. X
  1753. X    fh = &DB->fh[fileid];
  1754. X
  1755. X    /* If the file is open we set the file's sequence number to seqno to
  1756. X     * indicate that it is the most recently accessed file.
  1757. X     */
  1758. X    if( fh->any->fh != -1 )
  1759. X    {
  1760. X        fh->any->seqno = seqno++;
  1761. X        return S_OKAY;
  1762. X    }
  1763. X
  1764. X    if( ty_closeafile() == -1 )
  1765. X    {
  1766. X        puts("checkfile: could not find a file to close");
  1767. X        RETURN S_IOFATAL;
  1768. X    }
  1769. X
  1770. X    /* Now <cur_open> should be less than <max_open> so we can call
  1771. X     * ty_openfile() to reopen the file. If ty_openfile() cannot open the
  1772. X     * file the API function will return S_IOFATAL.
  1773. X     */
  1774. X
  1775. X    switch( fh->any->type )
  1776. X    {
  1777. X        case 'k':
  1778. X        case 'r':
  1779. X            rc = btree_dynopen(fh->key); 
  1780. X            break;
  1781. X        case 'd': 
  1782. X            rc = rec_dynopen(fh->rec);    
  1783. X            break;
  1784. X        case 'v': 
  1785. X            rc = vlr_dynopen(fh->vlr);    
  1786. X            break;
  1787. X    }
  1788. X
  1789. X    fh->any->seqno = seqno++;
  1790. X    typhoon.cur_open++;
  1791. X
  1792. X    return rc;
  1793. X}
  1794. X
  1795. X
  1796. X/*------------------------------ ty_openfile -------------------------------*\
  1797. X *
  1798. X * Purpose     : Opens a database file.
  1799. X *
  1800. X * Parameters: fp       - Pointer to file definition table entry.
  1801. X *               fh        - Pointer to file handle table entry.
  1802. X *               shared    - Open in shared mode?
  1803. X *
  1804. X * Returns     : db_status from d_keyopen(), d_recopen() or vlr_open().
  1805. X *
  1806. X */
  1807. X
  1808. Xty_openfile(fp, fh, shared)
  1809. XFile *fp;
  1810. XFh *fh;
  1811. Xint shared;
  1812. X{
  1813. X    char fname[255];
  1814. X    Key *key;
  1815. X    CMPFUNC cmp;
  1816. X    int rc;
  1817. X
  1818. X    /* If the maximum number of open files has been reached we return the
  1819. X     * CLOSEDPTR to indicate to the other ty_.. functions that the file
  1820. X     * descriptor points to a closed file and must be reopened.
  1821. X     */
  1822. X    if( typhoon.cur_open == typhoon.max_open )
  1823. X    {
  1824. X        if( ty_closeafile() == -1 )
  1825. X        {
  1826. X            puts("ty_openfile: could not find a file to close");
  1827. X            RETURN S_IOFATAL;
  1828. X        }
  1829. X    }
  1830. X
  1831. X    /* File is located in <DB->dbfpath> */
  1832. X    sprintf(fname, "%s%s", DB->dbfpath, fp->name);
  1833. X
  1834. X    switch( fp->type )
  1835. X    {
  1836. X        case 'r':
  1837. X            fh->key = btree_open(fname, sizeof(REF_ENTRY), fp->pagesize, (CMPFUNC)refentrycmp, 0, shared);
  1838. X            break;
  1839. X        case 'k':
  1840. X            key = DB->key + fp->id;
  1841. X
  1842. X            /* If the key has multiple fields or is sorted in descending order
  1843. X             * we use the compoundkeycmp function for key value comparisons.
  1844. X             */
  1845. X            if( key->fields > 1 || !DB->keyfield[key->first_keyfield ].asc )
  1846. X                cmp = compoundkeycmp;
  1847. X            else
  1848. X            {
  1849. X                Field *fld = &DB->field[ DB->keyfield[key->first_keyfield].field ];
  1850. X
  1851. X                cmp = keycmp[ fld->type & (FT_BASIC|FT_UNSIGNED) ];
  1852. X            }
  1853. X
  1854. X            fh->key = btree_open(fname, key->size, fp->pagesize, cmp,
  1855. X                                (key->type & KT_UNIQUE) ? 0 : 1, shared);
  1856. X            break;
  1857. X        case 'd':
  1858. X            /* Add the preamble to the size of the record */
  1859. X            fh->rec = rec_open(fname, DB->record[fp->id].size +
  1860. X                                        DB->record[fp->id].preamble, shared);
  1861. X            break;
  1862. X        case 'v':
  1863. X            fh->vlr = vlr_open(fname, fp->pagesize, shared);
  1864. X            break;
  1865. X    }
  1866. X
  1867. X    if( db_status == S_OKAY )
  1868. X    {
  1869. X        fh->any->type  = fp->type;
  1870. X        fh->any->seqno = seqno++;
  1871. X        typhoon.cur_open++;
  1872. X    }
  1873. X/*
  1874. X    else
  1875. X        printf("cannot open '%s' (db_status %d, errno %d)\n", fname, db_status, errno);
  1876. X*/
  1877. X    return db_status;
  1878. X}
  1879. X
  1880. X
  1881. X/*------------------------------- d_closefile ------------------------------*\
  1882. X *
  1883. X * Purpose     : Closes a database file.
  1884. X *
  1885. X * Parameters: fh    - Pointer to file handle table entry.
  1886. X *
  1887. X * Returns     : db_status from d_keyclose(), d_recclose() or vlr_close().
  1888. X *
  1889. X */
  1890. X
  1891. Xty_closefile(fh)
  1892. XFh *fh;
  1893. X{
  1894. X    /* If the file is already closed, we just return */
  1895. X    if( fh->any->fh != -1 )
  1896. X        typhoon.cur_open--;
  1897. X
  1898. X    switch( fh->any->type )
  1899. X    {
  1900. X        case 'k':
  1901. X        case 'r':
  1902. X            btree_close(fh->key); 
  1903. X            break;
  1904. X        case 'd': 
  1905. X            rec_close(fh->rec);    
  1906. X            break;
  1907. X        case 'v': 
  1908. X            vlr_close(fh->vlr);    
  1909. X            break;
  1910. X    }
  1911. X
  1912. X    /* Mark the file as closed */
  1913. X    fh->any->fh = -1;
  1914. X
  1915. X    return db_status;
  1916. X}
  1917. X
  1918. X
  1919. X
  1920. Xty_keyadd(key, value, ref)
  1921. XKey *key;
  1922. Xvoid *value;
  1923. Xulong ref;
  1924. X{
  1925. X    INDEX *idx;
  1926. X    int rc;
  1927. X
  1928. X    if( (rc = checkfile(key->fileid)) != S_OKAY )
  1929. X        return rc;
  1930. X
  1931. X    idx = DB->fh[key->fileid].key;
  1932. X    rc = btree_add(idx, value, ref);
  1933. X    btree_keyread(idx, CURR_KEYBUF);
  1934. X
  1935. X    return rc;
  1936. X}
  1937. X
  1938. X
  1939. Xty_keyfind(key, value, ref)
  1940. XKey *key;
  1941. Xvoid *value;
  1942. Xulong *ref;
  1943. X{
  1944. X    INDEX *idx;
  1945. X    int rc;
  1946. X
  1947. X    if( (rc = checkfile(key->fileid)) != S_OKAY )
  1948. X        return rc;
  1949. X
  1950. X    idx = DB->fh[key->fileid].key;
  1951. X    rc = btree_find(idx, value, ref);
  1952. X    btree_keyread(idx, CURR_KEYBUF);
  1953. X
  1954. X    return rc;
  1955. X}
  1956. X
  1957. X
  1958. X
  1959. Xty_keyfrst(key, ref)
  1960. XKey *key;
  1961. Xulong *ref;
  1962. X{
  1963. X    INDEX *idx;
  1964. X    int rc;
  1965. X
  1966. X    if( (rc = checkfile(key->fileid)) != S_OKAY )
  1967. X        return rc;
  1968. X
  1969. X    idx = DB->fh[key->fileid].key;
  1970. X    rc = btree_frst(idx, ref);
  1971. X    btree_keyread(idx, CURR_KEYBUF);
  1972. X
  1973. X    return rc;
  1974. X}
  1975. X
  1976. X
  1977. Xty_keylast(key, ref)
  1978. XKey *key;
  1979. Xulong *ref;
  1980. X{
  1981. X    INDEX *idx;
  1982. X    int rc;
  1983. X
  1984. X    if( (rc = checkfile(key->fileid)) != S_OKAY )
  1985. X        return rc;
  1986. X
  1987. X    idx = DB->fh[key->fileid].key;
  1988. X    rc = btree_last(idx, ref);
  1989. X    btree_keyread(idx, CURR_KEYBUF);
  1990. X
  1991. X    return rc;
  1992. X}
  1993. X
  1994. X
  1995. Xty_keyprev(key, ref)
  1996. XKey *key;
  1997. Xulong *ref;
  1998. X{
  1999. X    INDEX *idx;
  2000. X    int rc;
  2001. X
  2002. X    if( (rc = checkfile(key->fileid)) != S_OKAY )
  2003. X        return rc;
  2004. X
  2005. X    idx = DB->fh[key->fileid].key;
  2006. X    rc = btree_prev(idx, ref);
  2007. X    btree_keyread(idx, CURR_KEYBUF);
  2008. X
  2009. X    return rc;
  2010. X}
  2011. X
  2012. X
  2013. Xty_keynext(key, ref)
  2014. XKey *key;
  2015. Xulong *ref;
  2016. X{
  2017. X    INDEX *idx;
  2018. X    int rc;
  2019. X
  2020. X    if( (rc = checkfile(key->fileid)) != S_OKAY )
  2021. X        return rc;
  2022. X
  2023. X    idx = DB->fh[key->fileid].key;
  2024. X    rc = btree_next(idx, ref);
  2025. X    btree_keyread(idx, CURR_KEYBUF);
  2026. X
  2027. X    return rc;
  2028. X}
  2029. X
  2030. X               
  2031. Xty_keydel(key, value, ref)
  2032. XKey *key;
  2033. Xvoid *value;
  2034. Xulong ref;
  2035. X{
  2036. X    INDEX *idx;
  2037. X    int rc;
  2038. X
  2039. X    if( (rc = checkfile(key->fileid)) != S_OKAY )
  2040. X        return rc;
  2041. X
  2042. X    idx = DB->fh[key->fileid].key;
  2043. X    rc = btree_del(idx, value, ref);
  2044. X    btree_keyread(idx, CURR_KEYBUF);
  2045. X
  2046. X    return rc;
  2047. X}
  2048. X
  2049. X
  2050. Xty_recadd(rec, buf, recno)
  2051. XRecord *rec;
  2052. Xvoid *buf;
  2053. Xulong *recno;
  2054. X{
  2055. X    int rc;
  2056. X
  2057. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2058. X        return rc;
  2059. X
  2060. X    return rec_add(DB->fh[rec->fileid].rec, buf, recno);
  2061. X}
  2062. X
  2063. X
  2064. Xty_recwrite(rec, buf, recno)
  2065. XRecord *rec;
  2066. Xvoid *buf;
  2067. Xulong recno;
  2068. X{
  2069. X    int rc;
  2070. X
  2071. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2072. X        return rc;
  2073. X
  2074. X    return rec_write(DB->fh[rec->fileid].rec, buf, recno);
  2075. X}
  2076. X
  2077. X
  2078. Xty_recread(rec, buf, recno)
  2079. XRecord *rec;
  2080. Xvoid *buf;
  2081. Xulong recno;
  2082. X{
  2083. X    int rc;
  2084. X
  2085. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2086. X        return rc;
  2087. X
  2088. X    return rec_read(DB->fh[rec->fileid].rec, buf, recno);
  2089. X}
  2090. X
  2091. X
  2092. Xty_recdelete(rec, recno)
  2093. XRecord *rec;
  2094. Xulong recno;
  2095. X{
  2096. X    int rc;
  2097. X
  2098. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2099. X        return rc;
  2100. X
  2101. X    return rec_delete(DB->fh[rec->fileid].rec, recno);
  2102. X}
  2103. X
  2104. X
  2105. Xty_recfrst(rec, buf)
  2106. XRecord *rec;
  2107. Xvoid *buf;
  2108. X{
  2109. X    int rc;
  2110. X
  2111. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2112. X        return rc;
  2113. X
  2114. X    return rec_frst(DB->fh[rec->fileid].rec, buf);
  2115. X}
  2116. X
  2117. X
  2118. Xty_reclast(rec, buf)
  2119. XRecord *rec;
  2120. Xvoid *buf;
  2121. X{
  2122. X    int rc;
  2123. X
  2124. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2125. X        return rc;
  2126. X
  2127. X    return rec_last(DB->fh[rec->fileid].rec, buf);
  2128. X}
  2129. X
  2130. X
  2131. Xty_recnext(rec, buf)
  2132. XRecord *rec;
  2133. Xvoid *buf;
  2134. X{
  2135. X    int rc;
  2136. X
  2137. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2138. X        return rc;
  2139. X
  2140. X    return rec_next(DB->fh[rec->fileid].rec, buf);
  2141. X}
  2142. X
  2143. Xty_recprev(rec, buf)
  2144. XRecord *rec;
  2145. Xvoid *buf;
  2146. X{
  2147. X    int rc;
  2148. X
  2149. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2150. X        return rc;
  2151. X
  2152. X    return rec_prev(DB->fh[rec->fileid].rec, buf);
  2153. X}
  2154. X
  2155. Xulong ty_reccount(rec, count)
  2156. XRecord *rec;
  2157. Xulong *count;
  2158. X{
  2159. X    int rc;
  2160. X
  2161. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2162. X        return rc;
  2163. X
  2164. X    return rec_numrecords(DB->fh[rec->fileid].rec, count);
  2165. X}
  2166. X
  2167. Xty_reccurr(rec, recno)
  2168. XRecord *rec;
  2169. Xulong *recno;
  2170. X{
  2171. X    int rc;
  2172. X
  2173. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2174. X        return rc;
  2175. X
  2176. X    return rec_curr(DB->fh[rec->fileid].rec, recno);    
  2177. X}
  2178. X
  2179. Xty_vlradd(rec, buf, size, recno)
  2180. XRecord *rec;
  2181. Xvoid *buf;
  2182. Xunsigned size;
  2183. Xulong *recno;
  2184. X{
  2185. X    int rc;
  2186. X
  2187. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2188. X        return rc;
  2189. X
  2190. X    return vlr_add(DB->fh[rec->fileid].vlr, buf, size, recno);
  2191. X}
  2192. X
  2193. Xty_vlrwrite(rec, buf, size, recno)
  2194. XRecord *rec;
  2195. Xvoid *buf;
  2196. Xunsigned size;
  2197. Xulong recno;
  2198. X{
  2199. X    int rc;
  2200. X
  2201. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2202. X        return rc;
  2203. X
  2204. X    return vlr_write(DB->fh[rec->fileid].vlr, buf, size + rec->preamble, recno);
  2205. X}
  2206. X
  2207. X
  2208. Xunsigned ty_vlrread(rec, buf, recno, size)
  2209. XRecord *rec;
  2210. Xvoid *buf;
  2211. Xulong recno;
  2212. Xunsigned *size;
  2213. X{
  2214. X    int rc;
  2215. X
  2216. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2217. X        return rc;
  2218. X
  2219. X    return vlr_read(DB->fh[rec->fileid].vlr, buf, recno, size);
  2220. X}
  2221. X
  2222. Xty_vlrdel(rec, recno)
  2223. XRecord *rec;
  2224. Xulong recno;
  2225. X{
  2226. X    int rc;
  2227. X
  2228. X    if( (rc = checkfile(rec->fileid)) != S_OKAY )
  2229. X        return rc;
  2230. X
  2231. X    return vlr_del(DB->fh[rec->fileid].vlr, recno);
  2232. X}
  2233. X
  2234. X/* end-of-file */
  2235. END_OF_FILE
  2236.   if test 12101 -ne `wc -c <'typhoon/src/ty_io.c'`; then
  2237.     echo shar: \"'typhoon/src/ty_io.c'\" unpacked with wrong size!
  2238.   fi
  2239.   # end of 'typhoon/src/ty_io.c'
  2240. fi
  2241. if test -f 'typhoon/src/util/ddlpsym.c' -a "${1}" != "-c" ; then 
  2242.   echo shar: Will not clobber existing file \"'typhoon/src/util/ddlpsym.c'\"
  2243. else
  2244.   echo shar: Extracting \"'typhoon/src/util/ddlpsym.c'\" \(6862 characters\)
  2245.   sed "s/^X//" >'typhoon/src/util/ddlpsym.c' <<'END_OF_FILE'
  2246. X/*----------------------------------------------------------------------------
  2247. X * File    : ddlpsym.c
  2248. X * Program : ddlp
  2249. X * OS      : UNIX, OS/2, DOS
  2250. X * Author  : Thomas B. Pedersen
  2251. X *
  2252. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  2253. X *
  2254. X * Permission is hereby granted, without written agreement and without
  2255. X * license or royalty fees, to use, copy, modify, and distribute this
  2256. X * software and its documentation for any purpose, provided that the above
  2257. X * copyright notice and the following two  paragraphs appear (1) in all 
  2258. X * source copies of this software and (2) in accompanying documentation
  2259. X * wherever the programatic interface of this software, or any derivative
  2260. X * of it, is described.
  2261. X *
  2262. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  2263. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  2264. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  2265. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2266. X *
  2267. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  2268. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  2269. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  2270. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  2271. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  2272. X *
  2273. X * Description:
  2274. X *   Symbol table functions for ddlp.
  2275. X *
  2276. X * $Log: ddlpsym.c,v $
  2277. X * Revision 1.2  1994/09/17  16:00:52  tbp
  2278. X * typhoon.h and environ.h are now included from <>.
  2279. X *
  2280. X * Revision 1.1  1994/09/13  21:28:53  tbp
  2281. X * Added to repository.
  2282. X *
  2283. X * Added to repository.
  2284. X * 
  2285. X *
  2286. X *--------------------------------------------------------------------------*/
  2287. X
  2288. Xstatic char rcsid[] = "$Id: ddlpsym.c,v 1.2 1994/09/17 16:00:52 tbp Exp $";
  2289. X
  2290. X#include <stdio.h>
  2291. X#include <string.h>
  2292. X#ifndef UNIX
  2293. X#    include <stdlib.h>
  2294. X#endif
  2295. X#include <environ.h>
  2296. X#include "../ty_dbd.h"
  2297. X#include "ddlp.h"
  2298. X#include "ddlpsym.h"
  2299. X#include "ddlpglob.h"
  2300. X
  2301. X/*-------------------------- Function prototypes ---------------------------*/
  2302. Xstatic void print_struct        PRM( (sym_struct *, int); )
  2303. X
  2304. X/*---------------------------- Global variables ----------------------------*/
  2305. Xsym_struct    *first_str = NULL;            /* Pointer to start of struct table    */
  2306. Xsym_struct    *last_str = NULL;            /* Pointer to last struct             */
  2307. Xsym_struct    *cur_str = NULL;            /* Pointer to current struct         */
  2308. Xsym_struct    *structnest[NEST_MAX];        /* Structure nesting table            */
  2309. Xint            curnest = -1;                /* Current structure nesting        */
  2310. X
  2311. X
  2312. X/*------------------------------ sym_addmember -----------------------------*\
  2313. X *
  2314. X * Purpose:        This function adds a member to the structure currently
  2315. X *                being defined. The member is aligned according to <align>.
  2316. X * 
  2317. X * Params :        name    - struct member name.
  2318. X *                type    - member type, see FT_.. constants.
  2319. X *                ...        - If <type> == FT_STRUCT the 3rd parameter is a
  2320. X *                          pointer to a structdef record, otherwise it is
  2321. X *                          the size of the field.
  2322. X * 
  2323. X * Returns :     Nothing
  2324. X *
  2325. X */
  2326. X
  2327. Xvoid sym_addmember(name, type, struc)
  2328. Xchar *name;
  2329. Xint type;
  2330. Xsym_struct *struc;
  2331. X{
  2332. X    sym_struct *str = structnest[curnest];
  2333. X    sym_member *mem;
  2334. X
  2335. X    /* Make sure that this member name is not already used in this struct */
  2336. X    for( mem = str->first_member; mem; mem = mem->next )
  2337. X        if( !strcmp(name, mem->name) )
  2338. X        {
  2339. X            yyerror("duplicate member name '%s'", name);
  2340. X            return;
  2341. X        }
  2342. X
  2343. X    if( !(mem = (sym_member *)calloc(1,sizeof(*mem) + (dims-1) * sizeof(*mem->dim))) )
  2344. X        err_quit("out of memory");
  2345. X
  2346. X    if( type == FT_STRUCT )
  2347. X    {
  2348. X        mem->struc    = struc;
  2349. X        mem->size    = struc->size;
  2350. X    }
  2351. X    else
  2352. X        mem->size    = typeinfo[(type & FT_BASIC)-1].size;
  2353. X
  2354. X    strcpy(mem->name, name);
  2355. X    mem->type        = type;
  2356. X    mem->dims        = dims;
  2357. X    mem->elemsize    = mem->size;
  2358. X
  2359. X    /* If this member has arrays they must be stored and the size adjusted */
  2360. X    if( dims )
  2361. X    {
  2362. X        memcpy(mem->dim, dim, sizeof(*dim) * dims);
  2363. X
  2364. X        while( --dims )
  2365. X            dim[0] *= dim[dims];
  2366. X        mem->size *= dim[0];
  2367. X    }
  2368. X        
  2369. X    /* Add the new member to the member list */
  2370. X    if( str->last_member )
  2371. X        str->last_member->next = mem;
  2372. X    else
  2373. X        str->first_member = mem;
  2374. X    str->last_member = mem;
  2375. X    str->members++;
  2376. X
  2377. X    /*
  2378. X     * If the structure is a union all members must be at offset 0, and 
  2379. X     * the union must have the size of the biggest member.
  2380. X     */
  2381. X    if( str->is_union )
  2382. X    {
  2383. X        if( mem->size > str->size )
  2384. X            str->size = mem->size;
  2385. X    }
  2386. X    else
  2387. X    {
  2388. X        align_offset(&str->size, type);
  2389. X        mem->offset  = str->size;
  2390. X        str->size    += mem->size;
  2391. X    }
  2392. X}
  2393. X
  2394. X
  2395. Xvoid sym_addstruct(name, is_union)
  2396. Xchar *name;
  2397. Xint is_union;
  2398. X{
  2399. X    sym_struct *str;
  2400. X
  2401. X    /* Allocate new structdef and clear all fields */
  2402. X     if( !(str = (sym_struct *)calloc(1, sizeof *str)) )
  2403. X        err_quit("out of memory");
  2404. X
  2405. X    strcpy(str->name, name);
  2406. X    str->is_union        = is_union;
  2407. X
  2408. X    /* Insert structure in list */
  2409. X    if( !first_str )
  2410. X        first_str = str;
  2411. X    else
  2412. X        last_str->next = str;
  2413. X    cur_str = last_str = str;
  2414. X
  2415. X    structnest[++curnest] = str;
  2416. X}
  2417. X
  2418. X
  2419. Xvoid sym_endstruct()
  2420. X{
  2421. X    /* The size of a structure depends depends on the type of the last member
  2422. X     */
  2423. X/*    align_offset(&structnest[curnest]->size, FT_LONG);*/
  2424. X    align_offset(&structnest[curnest]->size, cur_str->last_member->type);
  2425. X
  2426. X    cur_str = structnest[--curnest];
  2427. X}
  2428. X
  2429. X
  2430. Xsym_struct *sym_findstruct(name, is_union)
  2431. Xchar *name;
  2432. Xint is_union;
  2433. X{
  2434. X    sym_struct *str = first_str;
  2435. X    
  2436. X    while( str )
  2437. X    {
  2438. X        if( !strcmp(name, str->name) && str->is_union == is_union )
  2439. X            return str;
  2440. X    
  2441. X        str = str->next;
  2442. X    }
  2443. X    
  2444. X    yyerror("unknown struct '%s'", name);
  2445. X    return NULL;
  2446. X}
  2447. X
  2448. X
  2449. Xsym_member *sym_findmember(str, name)
  2450. Xsym_struct *str;
  2451. Xchar *name;
  2452. X{
  2453. X    sym_member *mem = str->first_member;
  2454. X    
  2455. X    while( mem )
  2456. X    {
  2457. X        if( !strcmp(name, mem->name) )
  2458. X            return mem;
  2459. X
  2460. X        mem = mem->next;
  2461. X    }
  2462. X    
  2463. X    return NULL;        
  2464. X}
  2465. X
  2466. X
  2467. Xstatic void print_struct(str, nesting)
  2468. Xsym_struct *str;
  2469. X{
  2470. X    static char *type[] = { "struct", "union" };
  2471. X    sym_member *mem = str->first_member;
  2472. X    extern FILE *hfile;
  2473. X    int i;
  2474. X
  2475. X    fprintf(hfile, "%*s%s %s {  /* size %d */\n", nesting * 4, "",
  2476. X        type[str->is_union],
  2477. X        str->name,
  2478. X        str->size);
  2479. X
  2480. X    while( mem )
  2481. X    {
  2482. X        if( mem->type == FT_STRUCT )
  2483. X        {
  2484. X            if( mem->struc->printed )
  2485. X            {
  2486. X                fprintf(hfile, "%*s%s %s ",
  2487. X                    (nesting+1)*4, "",
  2488. X                    type[mem->struc->is_union],
  2489. X                    mem->struc->name);
  2490. X            }
  2491. X            else
  2492. X            {
  2493. X                mem->struc->printed = 1;            
  2494. X                print_struct(mem->struc, nesting+1);
  2495. X                fprintf(hfile, "%*s} ", (nesting+1)*4, "");
  2496. X            }
  2497. X        } 
  2498. X        else
  2499. X        {
  2500. X            fprintf(hfile, "%*s", (nesting+1) * 4, "");
  2501. X            if( mem->type & FT_UNSIGNED )
  2502. X                fprintf(hfile, "unsigned ");
  2503. X            fprintf(hfile, "%-8s", typeinfo[(mem->type & FT_BASIC) - 1].name);
  2504. X        }
  2505. X
  2506. X        fprintf(hfile, "%s", mem->name);
  2507. X
  2508. X        for( i=0; i<mem->dims; i++ )
  2509. X            fprintf(hfile, "[%d]", mem->dim[i]);
  2510. X
  2511. X        fprintf(hfile, ";\n");
  2512. X        mem = mem->next;
  2513. X    }        
  2514. X
  2515. X    if( nesting == 0 )
  2516. X        fprintf(hfile, "};\n\n");
  2517. X}
  2518. X
  2519. X
  2520. Xvoid print_structures()
  2521. X{
  2522. X    sym_struct *str = first_str;
  2523. X
  2524. X    while( str )
  2525. X    {
  2526. X        if( !str->printed )
  2527. X            print_struct(str, 0);
  2528. X        str = str->next;
  2529. X    }
  2530. X}
  2531. X
  2532. X
  2533. X/* end-of-file */
  2534. END_OF_FILE
  2535.   if test 6862 -ne `wc -c <'typhoon/src/util/ddlpsym.c'`; then
  2536.     echo shar: \"'typhoon/src/util/ddlpsym.c'\" unpacked with wrong size!
  2537.   fi
  2538.   # end of 'typhoon/src/util/ddlpsym.c'
  2539. fi
  2540. if test -f 'typhoon/src/util/imp_y.h' -a "${1}" != "-c" ; then 
  2541.   echo shar: Will not clobber existing file \"'typhoon/src/util/imp_y.h'\"
  2542. else
  2543.   echo shar: Extracting \"'typhoon/src/util/imp_y.h'\" \(215 characters\)
  2544.   sed "s/^X//" >'typhoon/src/util/imp_y.h' <<'END_OF_FILE'
  2545. X#define T_IMPORT 257
  2546. X#define T_RECORD 258
  2547. X#define T_STRUCT 259
  2548. X#define T_UNION 260
  2549. X#define T_IN 261
  2550. X#define T_IDENT 262
  2551. X#define T_STRING 263
  2552. Xtypedef union {
  2553. X    char      s[IDENT_LEN+1];
  2554. X} YYSTYPE;
  2555. Xextern YYSTYPE yylval;
  2556. END_OF_FILE
  2557.   if test 215 -ne `wc -c <'typhoon/src/util/imp_y.h'`; then
  2558.     echo shar: \"'typhoon/src/util/imp_y.h'\" unpacked with wrong size!
  2559.   fi
  2560.   # end of 'typhoon/src/util/imp_y.h'
  2561. fi
  2562. echo shar: End of archive 3 \(of 9\).
  2563. cp /dev/null ark3isdone
  2564. MISSING=""
  2565. for I in 1 2 3 4 5 6 7 8 9 ; do
  2566.     if test ! -f ark${I}isdone ; then
  2567.     MISSING="${MISSING} ${I}"
  2568.     fi
  2569. done
  2570. if test "${MISSING}" = "" ; then
  2571.     echo You have unpacked all 9 archives.
  2572.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2573. else
  2574.     echo You still must unpack the following archives:
  2575.     echo "        " ${MISSING}
  2576. fi
  2577. exit 0
  2578. exit 0 # Just in case...
  2579.