home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0010 - 0019 / ibm0010-0019 / ibm0010.tar / ibm0010 / CODE4-1.ZIP / SOURCE.ZIP / I4REINDE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-14  |  23.9 KB  |  985 lines

  1.  
  2. /*  i4reindex.c   (c)Copyright Sequiter Software Inc., 1987, 1988, 1989.  All rights reserved.
  3.  
  4.     Reindexes an Index File
  5. */
  6.  
  7. #include "d4base.h"
  8. #include "u4error.h"
  9.  
  10. #ifndef UNIX
  11.    #include <io.h>
  12.    #include <stdlib.h>
  13. #endif
  14.  
  15. #ifdef TURBO
  16.    #include <stdlib.h>
  17. #else
  18.    #include <malloc.h>
  19. #endif 
  20.  
  21. #include <string.h>
  22.  
  23. typedef struct
  24. {
  25.    char      *ptr      ;   /* Pointer to the current buffer position */
  26.    char      *end      ;   /* Pointer to the end buffer position */
  27.    long       disk      ;   /* Current Disk Position, Offset from Start;
  28.                  -1 Means nothing is on disk. */
  29. }  BUFFER ;
  30.  
  31. #define  NUM_BUFFER    600
  32.  
  33. static     int   add_key(KEY *), read_buffer(int), reindex(int), build_sort(int),
  34.                index_info( int ) ;
  35. static   long  build_index(void) ;
  36. static   char *get_key(void) ;
  37. extern     INDEX    *v4index ;
  38. extern     BLOCK    *v4block ;
  39. extern   BASE   *v4base ;
  40. extern     int     v4cur_base ;
  41. extern     int     v4last_base ;
  42.  
  43. static     KEY      key_value ;
  44. static     BUFFER  *buffer_ptr ;
  45. static     INDEX     *index_ptr  ;
  46. static     int      block_on   ;
  47. static     int      block_max  ;
  48. static     long      file_block ;
  49. static     int      group_len  ;
  50. static     int      key_len    ;
  51. static     int      key_len_4  ;
  52. static     int      keys_max   ;
  53. static     int      keys_mem   ;
  54. static     int      dos_file   ;
  55. static     int      i_small ;
  56. static     char     *name         ;
  57. static     char      temp_ptr[10];
  58. static     char      i_type ;
  59.  
  60. static     char *     large ;
  61. static     unsigned int    buf_size, spool_size ;
  62. static     int        num_spool, temp_file ;
  63.  
  64. static     long      qsort_times ;
  65. static     long      qsort_len ;
  66. static     long      num_read_buffer ;
  67. static     long      bytes_read_buffer ;
  68. static     long      disk_read_buffer ;
  69.  
  70. static  int  compare( char *, char * ) ;
  71.  
  72. static int  compare( one, two )
  73. char    *one,*two ;
  74. {
  75.    return( memcmp(one, two, key_len_4) ) ;
  76. }
  77.  
  78. #ifndef CLIPPER
  79.    static int  compare_doub( double *, double * ) ;
  80.  
  81.    static int  compare_doub( one, two )
  82.    double   *one, *two ;
  83.    {
  84.       if ( *one <= *two )
  85.      return( -1 ) ;
  86.       else
  87.      return(  1 ) ;
  88.    }
  89. #endif
  90.  
  91.  
  92. static int  build_sort( index_ref )
  93. int index_ref ;
  94. {
  95.    long      on_rec, count ;
  96.    unsigned int  on_key ;
  97.    int         rc, i, base_file, base_length, base_length2  ;
  98.    char     *eval_ptr, *large_ptr, *save_ptr, *on_ptr ;
  99.    BASE     *base_ptr ;
  100.  
  101.    base_ptr =  v4base +  v4cur_base ;
  102.    i_type   =  i4type( index_ref ) ;
  103.  
  104.    num_read_buffer = 0 ;
  105.    disk_read_buffer= 0 ;
  106.    bytes_read_buffer= 0 ;
  107.  
  108.    count       =  d4reccount() ;
  109.    on_key      =  0 ;
  110.    num_spool   =  0 ;
  111.  
  112.    large_ptr   =  large ;
  113.  
  114.    base_file   =  base_ptr->dos_file ;
  115.    base_length =  base_ptr->buffer_len ;
  116.    base_length2=  base_length << 1 ;
  117.    save_ptr    =  base_ptr->buffer ;
  118.    on_ptr      =  save_ptr -  base_length ;
  119.  
  120.    lseek( base_file, (long) d4ptr()->header_len, 0) ;
  121.    qsort_times = 0 ;
  122.    qsort_len   = 0 ;
  123.  
  124.    for ( on_rec = 1; on_rec <= count; on_rec++)
  125.    {
  126.       base_ptr->rec_num =  on_rec ;
  127.  
  128.       if ( on_rec & 1L )   /* On Odd Records */
  129.       {
  130.      rc =  read( base_file, on_ptr, base_length2) ;
  131.      if ( rc != base_length2 )
  132.      {
  133.         if ( on_rec != count ||  rc < base_length )
  134.         {
  135.            char buffer[34] ;
  136.            ltoa( on_rec, buffer, 10) ;
  137.            u4error( E_READ, base_ptr->name, "Record: ", buffer, (char *) 0) ;
  138.            return( -1) ;
  139.         }
  140.      }
  141.      base_ptr->buffer =  on_ptr ;
  142.      eval_ptr =  i4eval( index_ref) ;
  143.      base_ptr->buffer =  save_ptr ;
  144.       }
  145.       else
  146.      eval_ptr =  i4eval( index_ref) ;
  147.  
  148.       if ( eval_ptr == (char *) 0)  return( -1) ;
  149.  
  150.       memmove( large_ptr, eval_ptr, key_len)  ;
  151.       memmove( large_ptr+key_len, (char *)&on_rec, 4) ;
  152.       large_ptr += key_len_4 ;
  153.       on_key++ ;
  154.  
  155.       if ( on_key >=  keys_mem    &&  on_rec != count)
  156.       {
  157.      /* Buffer Full, Sort and Spool to Disk */
  158.      #ifdef CLIPPER
  159.         u4sort( large, on_key, key_len_4, compare) ;
  160.      #else
  161.         if ( i_type == 'C' )
  162.            u4sort( large, on_key, key_len_4, compare) ;
  163.         else
  164.            u4sort( large, on_key, key_len_4, compare_doub ) ;
  165.      #endif
  166.  
  167.      qsort_times++ ;
  168.      qsort_len += on_key*key_len_4 ;
  169.  
  170.      if ( num_spool == 0 )
  171.      {
  172.         /* Open the temporary File */
  173.         strcpy( temp_ptr, "D3XXXXXX") ;
  174.         mktemp( temp_ptr ) ;
  175.         if ( (temp_file =  u4open( temp_ptr, 1 )) < 0 )  return -1 ;
  176.         lseek( temp_file, 0L, 0) ;
  177.      }
  178.  
  179.      if ( write( temp_file, large, on_key*key_len_4) != on_key*key_len_4)
  180.      {
  181.         u4error( E_WRITE, temp_ptr, "Temporary Working File", (char *) 0 ) ;
  182.         return( -1 ) ;
  183.      }
  184.  
  185.      num_spool++ ;
  186.  
  187.      large_ptr =  large ;
  188.      on_key    =  0 ;
  189.       }
  190.    }
  191.  
  192.    /* Sort the buffer and spool if necessary */
  193.    #ifdef CLIPPER
  194.       u4sort( large, on_key, key_len_4, compare) ;
  195.    #else
  196.       if ( i_type == 'C' )
  197.      u4sort( large, on_key, key_len_4, compare) ;
  198.       else
  199.      u4sort( large, on_key, key_len_4, compare_doub ) ;
  200.    #endif
  201.    qsort_times++ ;
  202.    qsort_len += on_key*key_len_4 ;
  203.  
  204.    if ( num_spool > 0 )
  205.    {
  206.       if ( write( temp_file, large, on_key*key_len_4) != on_key*key_len_4)
  207.       {
  208.      u4error( E_WRITE, temp_ptr, "Temporary Work File", (char *) 0) ;
  209.      return( -1) ;
  210.       }
  211.       num_spool++ ;
  212.  
  213.       spool_size =  keys_mem * key_len_4 ;
  214.       buf_size     = (keys_mem / num_spool) * key_len_4 ;
  215.       if ( num_spool > NUM_BUFFER || keys_mem < num_spool )
  216.       {
  217.      u4error( E_INTERNAL, "BUILD_SORT", (char *) 0) ;
  218.      return( -1) ;
  219.       }
  220.  
  221.       for ( i=0; i< num_spool; i++ )
  222.       {
  223.      buffer_ptr[i].disk =  i*((long)spool_size) ;
  224.      buffer_ptr[i].end  =  large+ buf_size*(i+1) ;
  225.      read_buffer( i ) ;
  226.       }
  227.    }
  228.    else
  229.    {
  230.       /* One buffer was large enough. */
  231.       buffer_ptr->disk =  -1 ;
  232.       buffer_ptr->ptr  =  large ;
  233.       buffer_ptr->end  =  large +  count * key_len_4 ;
  234.       if ( count > 0)  num_spool =  1 ;
  235.    }
  236.  
  237.    i_small =  0 ;
  238.    return( 0) ;
  239. }
  240.  
  241.  
  242. static int read_buffer( i_buf )
  243. int i_buf ;
  244. {
  245.    unsigned int   bytes_read, ask_read, buffer_number ;
  246.  
  247.    num_read_buffer++ ;
  248.  
  249.    /* Is there anything still on disk ? */
  250.    if ( buffer_ptr[i_buf].disk < 0 )
  251.    {
  252.       if ( num_spool > 0)
  253.       {
  254.      /* Nothing left for Buffer */
  255.      memmove( (char *) (buffer_ptr+i_buf),
  256.           (char *) (buffer_ptr+num_spool-1), sizeof(BUFFER) ) ;
  257.      num_spool-- ;
  258.       }
  259.       return( 0) ;
  260.    }
  261.  
  262.    disk_read_buffer++ ;
  263.  
  264.    /* Calculate the buffer number from the current disk offset */
  265.    buffer_number =  (unsigned int) (buffer_ptr[i_buf].disk / spool_size) ;
  266.    buffer_ptr[i_buf].ptr =  large+ buffer_number* buf_size ;
  267.  
  268.    ask_read =  (unsigned int) ((long)spool_size* (buffer_number+1) - buffer_ptr[i_buf].disk) ;
  269.    if (ask_read > buf_size)  ask_read =  buf_size ;
  270.  
  271.    /* Read in the rest of the buffer from disk */
  272.  
  273.    lseek( temp_file, buffer_ptr[i_buf].disk, 0 ) ;
  274.    bytes_read =  read( temp_file, buffer_ptr[i_buf].ptr, ask_read) ;
  275.    if (bytes_read< (key_len+4) ||  bytes_read == 0xFFFF)
  276.    {
  277.       /* Nothing left for Buffer */
  278.       memmove( (char *) (buffer_ptr+i_buf),
  279.            (char *) (buffer_ptr+num_spool-1), sizeof(BUFFER) ) ;
  280.       num_spool-- ;
  281.       return( 0 ) ;
  282.    }
  283.  
  284.    buffer_ptr[i_buf].disk += bytes_read ;
  285.    if (bytes_read < buf_size ||
  286.        buffer_ptr[i_buf].disk/spool_size != buffer_number)
  287.    {
  288.        buffer_ptr[i_buf].disk = -1 ;
  289.    }
  290.  
  291.    bytes_read_buffer += bytes_read ;
  292.  
  293.    buffer_ptr[i_buf].end =  buffer_ptr[i_buf].ptr +  bytes_read ;
  294.  
  295.    return( 0) ;
  296. }
  297.  
  298.  
  299. static char  *get_key() /* Returns the next key in sorted order */
  300. {
  301.    char      *current ;
  302.    int          i ;
  303.  
  304.    if ( buffer_ptr[i_small].ptr >= buffer_ptr[i_small].end )
  305.     read_buffer( i_small) ;
  306.    if ( num_spool <= 0 )  return( (char *) 0) ;
  307.  
  308.    current =  buffer_ptr[0].ptr ;
  309.    i_small =  0 ;
  310.    for ( i= 1; i< num_spool; i++)
  311.    {
  312.       #ifndef CLIPPER
  313.       if ( i_type == 'C' )
  314.       {
  315.       #endif
  316.      if ( memcmp( buffer_ptr[i].ptr, current, key_len) < 0 )
  317.      {
  318.         current =  buffer_ptr[i].ptr ;
  319.         i_small =  i ;
  320.      }
  321.       #ifndef CLIPPER
  322.       }
  323.       else
  324.       {
  325.      if ( compare_doub( (double *) buffer_ptr[i].ptr,
  326.                 (double *) current ) < 0 )
  327.      {
  328.         current =  buffer_ptr[i].ptr ;
  329.         i_small =  i ;
  330.      }
  331.       }
  332.       #endif
  333.    }
  334.    buffer_ptr[i_small].ptr +=  key_len_4 ;
  335.  
  336.    return( current ) ;
  337. }
  338.  
  339.  
  340. #ifdef CLIPPER
  341. static long build_index()
  342. {
  343.    BLOCK  *block_ptr ;
  344.    KEY      *key_ptr;
  345.    char   *from_ptr,  last_ptr[MAX_KEY_SIZE+2] ;
  346.    int       i, first_time, i_block ;
  347.    long    num_recs ;
  348.  
  349.    num_recs   =  0 ;
  350.    first_time =  1 ;
  351.  
  352.    block_on =  block_max =  -1 ;
  353.    block_ptr=  v4block +    block_on ;
  354.  
  355.    file_block =  BLOCK_SIZE ;
  356.    lseek( dos_file, (long)BLOCK_SIZE, 0) ;
  357.  
  358.    while( 1)
  359.    {
  360.       from_ptr =  get_key() ;  /* Retrieves Keys in Sorted Order */
  361.  
  362.       if ( index_ptr->unique )
  363.       {
  364.      if ( ! first_time )
  365.      {
  366.         while ( from_ptr != (char *) 0 )
  367.         {
  368.            extern int  v4unique_error ;
  369.            if ( memcmp(from_ptr, last_ptr, key_len) != 0 )    break ;
  370.  
  371.            /* Filter out any repeat keys. */
  372.            if ( v4unique_error )
  373.            {
  374.           u4error( E_UNIQUE, index_ptr->name, (char *) 0) ;
  375.           return( -1) ;
  376.            }
  377.            from_ptr =  get_key() ;
  378.         }
  379.      }
  380.      if ( from_ptr != (char *) 0 )
  381.         memmove( last_ptr, from_ptr, sizeof(last_ptr ) ) ;
  382.  
  383.      first_time = 0 ;
  384.       }
  385.  
  386.       if ( from_ptr == (char *) 0 )
  387.       {
  388.      /* Observe
  389.         1.    Full Blocks will have been written if the entry which
  390.         points the the block has been entered.
  391.         2.    Either the bottom block may be written and give a starting
  392.         block pointer or the last block written is a good starting
  393.         block pointer.
  394.         3.    There may be one stranded entry which may be added later.
  395.         4.    file_block is the next address to be written
  396.      */
  397.  
  398.      /* The key_value is not yet active */
  399.      memset( &key_value, 0, (size_t) sizeof(key_value) ) ;
  400.  
  401.      /* Check for no Entries */
  402.      if ( block_max < 0 )
  403.      {
  404.         add_key( &key_value ) ;
  405.         v4block[0].num_keys =  0 ;
  406.  
  407.         if( write( dos_file, (char *)&v4block->num_keys, BLOCK_SIZE) != BLOCK_SIZE)
  408.         {
  409.            u4error( E_WRITE, name, (char *) 0) ;
  410.            return( -1) ;
  411.         }
  412.         file_block +=  BLOCK_SIZE ;
  413.      }
  414.      else
  415.      {
  416.         if ( v4block[0].num_keys == 0 )
  417.         {
  418.            while ( v4block[++block_on].num_keys == 0 ) ;
  419.  
  420.            block_ptr =  v4block + block_on ;
  421.            memcpy( &key_value, (char *) &block_ptr->num_keys +
  422.             block_ptr->pointers[block_ptr->num_keys-1], group_len) ;
  423.            block_ptr->num_keys-- ;
  424.            if ( block_ptr->num_keys != 0 )    block_on-- ;
  425.         }
  426.      }
  427.  
  428.      while( block_on < block_max )
  429.      {
  430.         block_on++ ;
  431.         block_ptr =  v4block+ block_on ;
  432.  
  433.         if ( block_ptr->num_keys > 0 )
  434.         {
  435.            key_ptr =  (KEY *) ((char *) &block_ptr->num_keys+
  436.                   block_ptr->pointers[block_ptr->num_keys]) ;
  437.            if ( block_on > 0 )
  438.           key_ptr->file_block =  file_block - BLOCK_SIZE ;
  439.  
  440.            if ( write( dos_file, (char *)&block_ptr->num_keys, BLOCK_SIZE) != BLOCK_SIZE)
  441.            {
  442.           u4error( E_WRITE, name, (char *) 0) ;
  443.           return( -1) ;
  444.            }
  445.            file_block +=  BLOCK_SIZE ;
  446.         }
  447.      }
  448.      index_ptr->root =  file_block -  BLOCK_SIZE ;
  449.      index_ptr->virtual_eof =  index_ptr->eof  =  0L ;
  450.  
  451.      return( num_recs ) ;
  452.       }
  453.       else
  454.      num_recs++ ;
  455.  
  456.       memcpy( key_value.value, from_ptr, key_len ) ;
  457.       memcpy( &key_value.rec_num, from_ptr+key_len, sizeof(long) ) ;
  458.       key_value.file_block =  0 ;
  459.       if( add_key( &key_value ) < 0 )  return -1 ;
  460.    }
  461. }
  462.  
  463. #else
  464.  
  465.  
  466. static long build_index()
  467. {
  468.    BLOCK  *block_ptr ;
  469.    KEY      *key_ptr   ;
  470.    char   *from_ptr,  last_ptr[102] ;
  471.    int       i, first_time ;
  472.    long    num_recs ;
  473.  
  474.    num_recs   =  0 ;
  475.    first_time =  1 ;
  476.  
  477.    block_on =  block_max =  0 ;
  478.    block_ptr=  v4block + block_on ;
  479.    memset( ((char *)block_ptr)+2*sizeof(int), 0,
  480.        (size_t) (sizeof(BLOCK)-2*sizeof(int)) ) ;
  481.  
  482.    block_ptr->num_keys =  keys_max ;
  483.    file_block =  1 ;
  484.    lseek( dos_file, (long)BLOCK_SIZE, 0) ;
  485.  
  486.    while( 1)
  487.    {
  488.       key_ptr =  (KEY *) ((char *)&block_ptr->key - group_len) ;
  489.       for( i=0; i< keys_max; i++)
  490.       {
  491.      from_ptr =  get_key() ;  /* Retrieves Keys in Sorted Order */
  492.      if ( index_ptr->unique )
  493.      {
  494.         if ( ! first_time )
  495.         {
  496.            while ( from_ptr != (char *) 0 )
  497.            {
  498.           extern int  v4unique_error ;
  499.  
  500.           if ( memcmp(from_ptr, last_ptr, key_len) != 0 )  break ;
  501.  
  502.           /* Filter out any repeat keys. */
  503.           if ( v4unique_error )
  504.           {
  505.              u4error( E_UNIQUE, index_ptr->name, (char *) 0) ;
  506.              return( -1) ;
  507.           }
  508.           from_ptr =  get_key() ;
  509.            }
  510.         }
  511.         if ( from_ptr != (char *) 0 )
  512.            memmove( last_ptr, from_ptr, sizeof(last_ptr ) ) ;
  513.         first_time = 0 ;
  514.      }
  515.  
  516.      if ( from_ptr == (char *) 0  && (i > 0 || block_max == block_on))
  517.      {
  518.         block_ptr->num_keys =  i ;
  519.         key_ptr   =  (KEY *) ((char *)&block_ptr->key+
  520.              i * group_len) ;
  521.         break ;
  522.      }
  523.  
  524.      if ( from_ptr == (char *) 0)
  525.      {
  526.         while( ++block_on)
  527.         {
  528.            block_ptr =  v4block+ block_on ;
  529.  
  530.            key_ptr     =  (KEY *) ((char *)&block_ptr->key+
  531.                 block_ptr->num_keys * group_len) ;
  532.  
  533.            if ( block_ptr->num_keys > 0)
  534.            {
  535.           if( write( dos_file, (char *)&block_ptr->num_keys, BLOCK_SIZE) != BLOCK_SIZE)
  536.           {
  537.              u4error( E_WRITE, name, (char *) 0) ;
  538.              return( -1) ;
  539.           }
  540.           key_ptr->file_block =  file_block++ ;
  541.            }
  542.            if ( block_on >= block_max)
  543.            {
  544.           index_ptr->root =  file_block -1 ;
  545.           index_ptr->eof  =  file_block ;
  546.           return( num_recs ) ;
  547.            }
  548.            if ( block_ptr->num_keys >= 0 )
  549.           add_key( key_ptr ) ;
  550.         }
  551.      }
  552.      else
  553.         num_recs++ ;
  554.  
  555.      key_ptr =  (KEY *)  ((char *)key_ptr + group_len) ;
  556.      memmove( key_ptr->value,   from_ptr, key_len )  ;
  557.      memmove( (char *) &key_ptr->rec_num, from_ptr+key_len, 4) ;
  558.       }
  559.       if( write( dos_file, (char *)&block_ptr->num_keys, BLOCK_SIZE) != BLOCK_SIZE)
  560.       {
  561.      u4error( E_WRITE, name, (char *) 0) ;
  562.      return( -1L ) ;
  563.       }
  564.       key_ptr->file_block = file_block++ ;
  565.       if( add_key(key_ptr ) < 0) return( -1L ) ;
  566.       key_ptr->file_block = 0 ;
  567.    }
  568. }
  569.  
  570. #endif
  571.  
  572.  
  573. #ifdef CLIPPER
  574.  
  575. static int add_key( key_ptr )
  576. KEY           *key_ptr ;
  577. {
  578.    BLOCK *block_ptr ;
  579.    int      i, i_block ;
  580.  
  581.    block_on ++ ;
  582.    block_ptr =    v4block+ block_on ;
  583.  
  584.    if ( block_on > block_max )
  585.    {
  586.       /* Initialization for this block level */
  587.       memset( ((char *)block_ptr)+2*sizeof(int), 0,
  588.           (size_t) (sizeof(BLOCK)-2*sizeof(int)) ) ;
  589.  
  590.       i_block =  keys_max*2 + 4 ;
  591.       for (i=0; i<= keys_max; i++, i_block+= group_len)
  592.      block_ptr->pointers[i] =  i_block ;
  593.  
  594.       block_ptr->num_keys =  0 ;
  595.       block_max       =  block_on ;
  596.    }
  597.  
  598.    if ( block_ptr->num_keys >= keys_max )
  599.    {
  600.       memmove( (char *)&block_ptr->num_keys +
  601.             block_ptr->pointers[block_ptr->num_keys],
  602.            (char *) &key_ptr->file_block, 4) ;
  603.  
  604.       if( write(dos_file, (char *) &block_ptr->num_keys, BLOCK_SIZE) != BLOCK_SIZE)
  605.       {
  606.      u4error( E_WRITE, name, (char *) 0) ;
  607.      return( -1) ;
  608.       }
  609.       key_ptr->file_block =  file_block ;
  610.       file_block +=  BLOCK_SIZE ;
  611.       if( add_key( key_ptr) < 0)  return( -1) ;
  612.  
  613.       block_ptr->num_keys =  0 ;
  614.    }
  615.    else
  616.    {
  617.       memmove( (char *)&block_ptr->num_keys +
  618.             block_ptr->pointers[block_ptr->num_keys],
  619.            (char *) key_ptr, group_len) ;
  620.       block_ptr->num_keys++ ;
  621.    }
  622.  
  623.    block_on -- ;
  624.    return(0) ;
  625. }
  626.  
  627. #else
  628.  
  629. static int add_key( key_ptr )
  630. KEY           *key_ptr ;
  631. {
  632.    BLOCK *block_ptr ;
  633.  
  634.    block_on ++ ;
  635.    block_ptr =    v4block+ block_on ;
  636.  
  637.    if ( block_on > block_max )
  638.    {
  639.       /* Initialization for this block level */
  640.       memset( ((char *)block_ptr)+2*sizeof(int), 0,
  641.           (size_t) (sizeof(BLOCK)-2*sizeof(int)) ) ;
  642.       block_ptr->num_keys =  -1 ;
  643.       block_max =  block_on ;
  644.    }
  645.  
  646.    key_ptr->rec_num =  0 ;
  647.  
  648.    if ( ++block_ptr->num_keys >= keys_max )
  649.    {
  650.       memmove( (char *)&block_ptr->key + block_ptr->num_keys*group_len,
  651.            (char *) key_ptr, 4) ;
  652.  
  653.       if( write(dos_file, (char *) &block_ptr->num_keys, BLOCK_SIZE) != BLOCK_SIZE)
  654.       {
  655.      u4error( E_WRITE, name, (char *) 0) ;
  656.      return( -1) ;
  657.       }
  658.       key_ptr->file_block =  file_block++ ;
  659.       if( add_key( key_ptr) < 0)  return( -1) ;
  660.  
  661.       block_ptr->num_keys = -1 ;
  662.    }
  663.    else
  664.       memmove( (char *)&block_ptr->key + block_ptr->num_keys*group_len,
  665.            (char *) key_ptr, group_len) ;
  666.  
  667.    block_on -- ;
  668.    return(0) ;
  669. }
  670.  
  671. #endif
  672.  
  673.  
  674. static int  index_info( index_ref )
  675. int  index_ref ;
  676. {
  677.    INDEX  *index_ptr ;
  678.    char   *eval_ptr, *expr_ptr ;
  679.  
  680.    index_ptr =    v4index +  index_ref ;
  681.    memset( d4ptr()->buffer, (int) ' ', (size_t) d4ptr()->buffer_len) ;
  682.  
  683.    eval_ptr =  i4eval( index_ref) ;
  684.    if ( eval_ptr == (char *) 0)  return( -1) ;
  685.  
  686.    index_ptr->i_type =    e4type() ;
  687.  
  688.    #ifndef CLIPPER
  689.       if ( e4type() == 'D' || e4type() == 'N' || e4type() == 'F' )
  690.      index_ptr->int_or_date =  1 ;
  691.       else
  692.      index_ptr->int_or_date =  0 ;
  693.    #endif
  694.  
  695.    key_len =  0 ;
  696.  
  697.    if ( e4type() == 'D' )
  698.       key_len =  8 ;
  699.  
  700.    if ( e4type() == 'C' )
  701.       key_len =  strlen( eval_ptr ) ;
  702.  
  703.    if ( e4type() == 'N' || e4type() == 'F' )
  704.    {
  705.       #ifdef CLIPPER
  706.          char  buf[20] ;
  707.          int   cur_digits, cur_dec, on_digits, i_buf ;
  708.          long  f_ref ;
  709.      int   i_expr ;
  710.  
  711.      /* Analyse the Expression to Determine the Maximum Decimals and Len */
  712.      i_buf =  cur_digits =    cur_dec =  0 ;
  713.  
  714.      expr_ptr =  index_ptr->expression ;
  715.      for ( i_expr = 0; ; i_expr++ )
  716.      {
  717.         if ( u4name_char( expr_ptr[i_expr] ) )
  718.         {
  719.            if ( i_buf < sizeof(buf) )
  720.           buf[i_buf++] =  expr_ptr[i_expr] ;
  721.         }
  722.         else
  723.         {
  724.            buf[i_buf] =  '\0' ;
  725.            i_buf =    0 ;
  726.  
  727.            f_ref =    f4ref( buf ) ;
  728.            if ( f_ref >= 0 )
  729.            {
  730.           on_digits =  f4width(f_ref) ;
  731.           if ( f4decimals(f_ref) > 0 )
  732.              on_digits -=  f4decimals(f_ref)+1 ;
  733.  
  734.           if ( on_digits > cur_digits)     cur_digits =  on_digits ;
  735.  
  736.           if ( f4decimals(f_ref) > cur_dec) cur_dec = f4decimals(f_ref);
  737.            }
  738.  
  739.            if ( i_expr >= sizeof(index_ptr->expression) )  break ;
  740.         }
  741.      }
  742.  
  743.      index_ptr->key_dec =  cur_dec ;
  744.      key_len =  cur_digits ;
  745.      if ( cur_dec > 0 )  key_len +=  cur_dec+1 ;
  746.       #else
  747.      key_len =  sizeof(double) ;
  748.       #endif
  749.    }
  750.  
  751.    if ( key_len > MAX_KEY_SIZE || key_len <= 0 )
  752.    {
  753.        u4error( E_KEY_LEN, name, "Expression:", index_ptr->expression, (char *) 0) ;
  754.        return( -1) ;
  755.    }
  756.  
  757.    index_ptr->key_len =  key_len ;
  758.    index_ptr->version =  index_ptr->old_version + 1 ;
  759.  
  760.    #ifdef CLIPPER
  761.      index_ptr->sign   =  6 ;
  762.       index_ptr->group_len =  group_len =  key_len+8 ;
  763.       index_ptr->keys_half =  (1020/ (group_len+2) - 1)/ 2;
  764.       index_ptr->keys_max  =  keys_max    =  index_ptr->keys_half *2 ;
  765.       if ( keys_max < 2 )
  766.       {
  767.      u4error( E_BAD_NDX, index_ptr->name, (char *) 0 ) ;
  768.      return( -1 ) ;
  769.       }
  770.    #else
  771.       index_ptr->group_len =  group_len =  key_len+8 + key_len%2 ;
  772.       index_ptr->keys_max  =  keys_max    =  504/ index_ptr->group_len ;
  773.       if ( keys_max < 4 )
  774.       {
  775.      u4error( E_BAD_NDX, index_ptr->name, (char *) 0 ) ;
  776.      return( -1 ) ;
  777.       }
  778.    #endif
  779.  
  780.    dos_file        =  index_ptr->dos_file ;
  781.    name         =  index_ptr->name ;
  782.    key_len_4 =    key_len+4 ;
  783.  
  784.    return 0 ;
  785. }
  786.  
  787. static int  write_header(void) ;
  788. static int  write_header()
  789. {
  790.    char  buffer[BLOCK_SIZE] ;
  791.    int   header_len ;
  792.  
  793.    memset( buffer, 0, BLOCK_SIZE ) ;
  794.  
  795.    lseek( dos_file, 0L, 0) ;
  796.    #ifdef CLIPPER
  797.       chsize(dos_file, index_ptr->root+ (long) BLOCK_SIZE ) ;
  798.       header_len =  (char *)(v4index+1) - (char *) &v4index->sign ;
  799.       memcpy( buffer, &index_ptr->sign, header_len ) ;
  800.    #else
  801.       chsize(dos_file, index_ptr->eof*BLOCK_SIZE) ;
  802.       header_len =  (char *)(v4index+1) - (char *) &v4index->root  ;
  803.       memcpy( buffer, (char *) &index_ptr->root, header_len ) ;
  804.    #endif
  805.    if ( write( dos_file, (char *) buffer, BLOCK_SIZE) != BLOCK_SIZE )
  806.    {
  807.       u4error( E_WRITE, name, (char *) 0 ) ;
  808.       return( -1 ) ;
  809.    }
  810.  
  811.    return 0 ;
  812. }
  813.  
  814.  
  815. static int reindex( index_ref )
  816. int     index_ref ;
  817. {
  818.    long      minimum, lrc ;
  819.    int         rc ;
  820.    unsigned int  allocated ;
  821.  
  822.    index_ptr =    v4index + index_ref ;
  823.  
  824.    if ( index_ptr->compile != (char *) 0 )  h4free_memory( index_ptr->compile) ;
  825.    if ( e4parse( index_ptr->expression, &index_ptr->compile) < 0)  return(-1) ;
  826.  
  827.    if ( index_info(index_ref) < 0 )  return -1 ;
  828.  
  829.    minimum =  key_len_4 ;
  830.    while (1)
  831.    {
  832.       /* Allocate at least the minumim memory */
  833.  
  834.       large  = h4alloc_try( allocated = 0xFFDE ) ;
  835.       while ( large == (char *) 0)
  836.       {
  837.      allocated =  allocated/2 ;
  838.      if ( allocated <= (unsigned int) minimum )
  839.      {
  840.         allocated    =  (unsigned int) minimum ;
  841.         large =  h4alloc_try( allocated) ;
  842.         if ( large == (char *) 0)
  843.         {
  844.            u4error( E_INDEX, name, "More Memory Needed.", (char *) 0) ;
  845.            return( -1) ;
  846.         }
  847.      }
  848.      else
  849.         large =  h4alloc_try( allocated) ;
  850.       }
  851.  
  852.       keys_mem    =  allocated/key_len_4 ;
  853.  
  854.       /* Raise the minimum if necessary */
  855.  
  856.       if ( (long)keys_mem * ( (keys_mem < NUM_BUFFER) ? keys_mem : NUM_BUFFER) < d4reccount() )
  857.       {
  858.      /* Raise the minimum as it is not enough */
  859.      minimum =  (keys_mem+1)*key_len_4 ;
  860.      if ( minimum >= 0xFFE0 )
  861.      {
  862.         u4error( E_INDEX, name, "Too Many Records to Index.", (char *) 0) ;
  863.         return( -1) ;
  864.      }
  865.      h4free_memory( large ) ;
  866.       }
  867.       else
  868.      break ;
  869.    }
  870.  
  871.    temp_ptr[0] =  '\0' ;
  872.  
  873.    /* Sort the Information */
  874.    if ( build_sort(index_ref) < 0)
  875.    {
  876.       if ( temp_ptr[0] != '\0')
  877.       {
  878.      close( temp_file ) ;
  879.      #ifdef TURBO
  880.         unlink(temp_ptr) ;
  881.      #else
  882.         remove(temp_ptr) ;
  883.      #endif
  884.       }
  885.       return( -1 ) ;
  886.    }
  887.  
  888.    chsize(dos_file, (long) BLOCK_SIZE ) ;
  889.  
  890.    /* Build the Index File */
  891.    lrc =  build_index() ;
  892.    if ( temp_ptr[0] != '\0')
  893.    {
  894.      close( temp_file ) ;
  895.      #ifdef TURBO
  896.         rc = unlink(temp_ptr) ;
  897.      #else
  898.         rc = remove(temp_ptr) ;
  899.      #endif
  900.      if ( rc != 0 )
  901.      {
  902.         u4error( E_CLOSE, "Temporary Working File", temp_ptr, (char *) 0 ) ;
  903.         return( -1 ) ;
  904.      }
  905.    }
  906.    if ( lrc < 0)   return( -1) ;
  907.  
  908.    /* Write the Index File Control Information (Block 0) */
  909.    if ( write_header() < 0 )  return -1 ;
  910.  
  911.    #ifdef CLIPPER
  912.       if ( key_value.rec_num != 0 )
  913.       {
  914.      if ( i4add( index_ref, key_value.value, key_value.rec_num ) < 0 )
  915.         return -1 ;
  916.       }
  917.    #endif
  918.  
  919.    if ( lrc != d4reccount() &&    ! index_ptr->unique )
  920.    {
  921.       char buffer[10] ;
  922.       c4ltoa( lrc, buffer, 8 ) ;
  923.       buffer[8] = '\0' ;
  924.       u4error( E_INTERNAL, "NUMBER REINDEXED:", buffer, (char *) 0 ) ;
  925.       return( -1 ) ;
  926.    }
  927.  
  928.    return( 0 ) ;
  929. }
  930.  
  931.  
  932. i4reindex( index_ref )
  933. int  index_ref ;
  934. {
  935.    int      rc, index_on, old_base ;
  936.  
  937.    /* First Reclaim Block Memory */
  938.    old_base  =    v4cur_base ;
  939.    for ( v4cur_base = v4last_base; v4cur_base >= 0; v4cur_base = v4base[v4cur_base].prev )
  940.       for ( index_on =  v4base[v4cur_base].index_ref; index_on >= 0; index_on = v4index[index_on].prev )
  941.      if ( i4free( index_on ) < 0 )  return -1 ;
  942.  
  943.    if ( index_ref >= 0)
  944.       v4cur_base =  v4index[index_ref].base_ref ;
  945.    else
  946.       v4cur_base =  old_base ;
  947.  
  948.    if ( d4lock( -1L, 1) < 0) return( -1) ;
  949.  
  950.    rc = 0 ;
  951.    buffer_ptr =  (BUFFER *) h4alloc( NUM_BUFFER * sizeof(BUFFER) ) ;
  952.  
  953.    if ( index_ref >= 0 )
  954.    {
  955.       large     =  (char *) 0 ;
  956.       if ( i4lock( index_ref, 1) < 0) return( -1) ;
  957.       if ( reindex( index_ref ) < 0)  rc =  -1 ;
  958.  
  959.       if ( large != (char *) 0) h4free_memory( large ) ;
  960.       i4unlock( index_ref ) ;
  961.    }
  962.    else
  963.    {
  964.       index_on =  d4ptr()->index_ref ;
  965.       while (index_on >= 0)
  966.       {
  967.      large =  (char *) 0 ;
  968.  
  969.      if ( i4lock( index_on, 1) < 0) return( -1) ;
  970.      if ( reindex( index_on) < 0) rc =  -1 ;
  971.  
  972.      if ( large != (char *) 0) h4free_memory( large ) ;
  973.      i4unlock( index_on ) ;
  974.  
  975.      index_on =  v4index[index_on].prev ;
  976.       }
  977.    }
  978.    memset( v4base[v4cur_base].buffer, (int) ' ', v4base[v4cur_base].buffer_len);
  979.    v4cur_base =  old_base ;
  980.    h4free_memory( (char *) buffer_ptr ) ;
  981.  
  982.    return( rc) ;
  983. }
  984.  
  985.