/* i4create.c   (c)Copyright Sequiter Software Inc., 1990-1994.  All rights reserved. */

#include "d4all.h"
#ifndef S4UNIX
#ifdef __TURBOC__
#pragma hdrstop
#endif
#endif

#ifndef S4INDEX_OFF
#ifndef S4OFF_WRITE

#include "r4reinde.h"

#ifndef N4OTHER

INDEX4 *S4FUNCTION i4create( DATA4 *d4, char *file_name, TAG4INFO *tag_data )
{
  INDEX4 *i4 ;
  CODE4 *c4 ;
  TAG4 *tag_ptr ;
  char buf[258] ;
  int i, rc ;
#ifndef S4OPTIMIZE_OFF
  int has_opt ;
#endif

#ifdef S4VBASIC
  if ( c4parm_check( d4, 2, E4_I4CREATE ) )
    return 0 ;
#endif

#ifdef S4DEBUG
  if ( d4 == 0 || tag_data == 0 )
    e4severe( e4parm, E4_I4CREATE ) ;

  if ( file_name )
    u4name_piece( buf, sizeof( buf ), file_name, 0, 0 ) ;
  else
    u4name_piece( buf, sizeof( buf ), d4->file.name, 0, 0 ) ;
  if ( d4index( d4, buf ) )
  {
    e4( d4->code_base, e4info, E4_INFO_IAO ) ;
    return 0 ;
  }
#endif

  c4 = d4->code_base ;
  if ( c4->error_code < 0 )
    return 0 ;
  c4->error_code = 0 ;  /* Make sure it is not 'r4unique' or 'r4no_create'. */

#ifndef S4OPTIMIZE_OFF
  if ( c4->has_opt )
  {
    has_opt = 1 ;
    d4opt_suspend( c4 ) ;
  }
  else
    has_opt = 0 ;
#endif  /* not S4OPTIMIZE_OFF */

#ifndef S4SINGLE
  if ( d4lock_file( d4 ) )
    return 0 ;
#endif

  i4 = (INDEX4 *)mem4create_alloc( c4, &c4->index_memory, c4->mem_start_index, sizeof(INDEX4), c4->mem_expand_index, 0 ) ;
  if ( i4 == 0 )
  {
    e4( c4, e4memory, 0 ) ;
    return 0 ;
  }

  i4->code_base = c4 ;
  i4->data = d4 ;

  memset(buf,0,sizeof(buf));
  if ( file_name )
    u4ncpy( buf, file_name, sizeof(buf) ) ;
  else
    u4name_piece( buf, sizeof( buf ), d4->file.name, 1, 0 ) ;

#ifdef S4FOX
#ifdef S4UNIX
  u4name_ext( buf, sizeof(buf), "cdx", 0 ) ;
#else
  u4name_ext( buf, sizeof(buf), "CDX", 0 ) ;
#endif
#else
#ifdef S4UNIX
  u4name_ext( buf, sizeof(buf), "mdx", 0 ) ;
#else
  u4name_ext( buf, sizeof(buf), "MDX", 0 ) ;
#endif
#endif

  rc = file4create( &i4->file, c4, buf, 1 ) ;
  if ( rc )
  {
    if ( rc > 0 )
      c4->error_code = rc ;

    i4close( i4 ) ;
    return 0 ;
  }

  l4add( &d4->indexes, i4 ) ;

#ifdef S4FOX
  i4->block_memory = mem4create( c4, c4->mem_start_block,
                                (sizeof(B4BLOCK)) + B4BLOCK_SIZE - (sizeof(B4STD_HEADER)) - (sizeof(B4NODE_HEADER)), c4->mem_expand_block, 0 ) ;
  if ( i4->block_memory == 0 )
  {
    i4close( i4 ) ;
    return 0 ;
  }

  if ( c4->tag_memory == 0 )
  {
    c4->tag_memory = mem4create( c4, c4->mem_start_tag, sizeof(TAG4), c4->mem_expand_tag, 0 ) ;
    if ( c4->tag_memory == 0 )
      return 0 ;
  }

  i4->tag_index = (TAG4 *) mem4alloc( c4->tag_memory ) ;
  if ( i4->tag_index == 0 )
  {
    e4( c4, e4memory, 0 ) ;
    return 0 ;
  }

  i4->tag_index->code_base = c4 ;
  i4->tag_index->index = i4 ;
  i4->tag_index->header.type_code = 0xE0 ;  /* compound, compact */
  i4->tag_index->header.filter_len = 1 ;
  i4->tag_index->header.filter_pos = 1 ;
  i4->tag_index->header.expr_len = 1 ;
  i4->tag_index->header.expr_pos = 0 ;
  i4->tag_index->header.key_len = 10 ;

  u4name_piece( i4->tag_index->alias, sizeof(i4->tag_index->alias), buf, 0, 0 ) ;

  for ( i = 0; tag_data[i].name; i++ )
  {
    tag_ptr = (TAG4 *) mem4alloc( c4->tag_memory ) ;
    if ( tag_ptr == 0 )
      e4(  c4, e4memory, 0 ) ;

    tag_ptr->code_base = c4 ;
    tag_ptr->index = i4 ;

    u4ncpy( tag_ptr->alias, tag_data[i].name, sizeof(tag_ptr->alias) ) ;
#ifndef S4UNIX
    c4upper( tag_ptr->alias ) ;
#endif

    tag_ptr->header.type_code  = 0x60 ;  /* compact */
    if ( tag_data[i].unique )
    {
      tag_ptr->header.type_code += 0x01 ;
      tag_ptr->unique_error = tag_data[i].unique ;

#ifdef S4DEBUG
      if ( tag_data[i].unique != e4unique &&
          tag_data[i].unique != r4unique &&
          tag_data[i].unique != r4unique_continue )
        e4severe( e4parm, E4_PARM_UNI ) ;
#endif
    }
    if ( tag_data[i].descending)
    {
      tag_ptr->header.descending = 1 ;
#ifdef S4DEBUG
      if ( tag_data[i].descending != r4descending )
        e4severe( e4parm, E4_PARM_FLA ) ;
#endif
    }

#ifdef S4DEBUG
    if ( tag_data[i].expression == 0 )
      e4severe( e4parm, E4_PARM_TAG ) ;
#endif

    tag_ptr->expr = expr4parse( d4, tag_data[i].expression ) ;
    if ( tag_ptr->expr == 0 )
    {
      mem4free( c4->tag_memory, tag_ptr ) ;
      i4close( i4 );
      return 0;
    }

    tag_ptr->header.expr_len = (short) (strlen( tag_ptr->expr->source ) + 1) ;
    if( tag_ptr->header.expr_len > I4MAX_EXPR_SIZE )
      e4( d4->code_base, e4index, E4_EXPR_OM ) ;
    if ( tag_data[i].filter != 0 )
      if ( *( tag_data[i].filter ) != '\0' )
      {
        tag_ptr->header.type_code += 0x08 ;
        tag_ptr->filter = expr4parse( d4, tag_data[i].filter ) ;
        if (tag_ptr->filter)
          tag_ptr->header.filter_len = (short)strlen( tag_ptr->filter->source ) ;
      }
    tag_ptr->header.filter_len++ ;  /* minimum of 1, for the '\0' */
    if( tag_ptr->header.filter_len > I4MAX_EXPR_SIZE )
      e4( d4->code_base, e4index, E4_EXPR_OM ) ;
    tag_ptr->header.filter_pos = tag_ptr->header.expr_len ;

    if ( c4->error_code < 0 )
      break ;
    l4add( &i4->tags, tag_ptr ) ;
  }
#else                /* if not S4FOX   */
  i4->header.two = 2 ;
  u4yymmdd( i4->header.create_date ) ;

  if ( file_name == 0 )
    i4->header.is_production = 1 ;

  i4->header.num_slots = 0x30 ;
  i4->header.slot_size = 0x20 ;

  u4name_piece( i4->header.data_name, sizeof( i4->header.data_name ), d4->file.name, 0, 0 ) ;
  i4->header.block_chunks = (short)(c4->mem_size_block/512) ;

#ifdef S4DEBUG
  if ( i4->header.block_chunks < 2 || i4->header.block_chunks > 63 )   /* disallowed for compatibility reasons */
    e4severe( e4info, E4_INFO_BLO ) ;
#endif

  i4->header.block_rw = (short)(i4->header.block_chunks * I4MULTIPLY) ;

  i4->block_memory = mem4create( c4, c4->mem_start_block,
                                (sizeof(B4BLOCK)) + i4->header.block_rw -
                                (sizeof(B4KEY_DATA)) - (sizeof(short)) - (sizeof(char[6])),
                                c4->mem_expand_block, 0 ) ;
  if ( i4->block_memory == 0 )
  {
    i4close( i4 ) ;
    return 0 ;
  }

  for ( i = 0 ; tag_data[i].name ; i++ )
  {
    i4->header.num_tags++ ;

    if ( c4->tag_memory == 0 )
    {
      c4->tag_memory = mem4create( c4, c4->mem_start_tag, sizeof(TAG4),
                                  c4->mem_expand_tag, 0 ) ;
      if ( c4->tag_memory == 0 )
        return 0 ;
    }

    tag_ptr = (TAG4 *) mem4alloc( c4->tag_memory ) ;
    if ( tag_ptr == 0 )
    {
      e4(  c4, e4memory, 0 ) ;
      return 0 ;
    }
    memset( (void *)tag_ptr,0, sizeof(TAG4) ) ;

    tag_ptr->code_base = c4 ;
    tag_ptr->index = i4 ;

    u4ncpy( tag_ptr->alias, tag_data[i].name, sizeof(tag_ptr->alias) ) ;
#ifndef S4UNIX
    c4upper( tag_ptr->alias ) ;
#endif

    tag_ptr->header.type_code  = 0x10 ;
    if ( tag_data[i].unique )
    {
      tag_ptr->header.type_code += 0x40 ;
      tag_ptr->header.unique = 0x4000 ;
      tag_ptr->unique_error = tag_data[i].unique ;

#ifdef S4DEBUG
      if ( tag_data[i].unique != e4unique &&
          tag_data[i].unique != r4unique &&
          tag_data[i].unique != r4unique_continue )
        e4severe( e4parm, E4_PARM_UNI ) ;
#endif
    }
    if ( tag_data[i].descending)
    {
      tag_ptr->header.type_code += 0x08 ;
#ifdef S4DEBUG
      if ( tag_data[i].descending != r4descending )
        e4severe( e4parm, E4_PARM_FLA ) ;
#endif
    }

#ifdef S4DEBUG
    if ( tag_data[i].expression == 0 )
      e4severe( e4parm, E4_PARM_TAG ) ;
#endif

    tag_ptr->expr = expr4parse( d4, tag_data[i].expression ) ;
    if( tag_ptr->expr == 0 )
    {
      mem4free( c4->tag_memory, tag_ptr ) ;
      i4close( i4 );
      return 0;
    }
    if ( tag_data[i].filter != 0 )
      if ( *(tag_data[i].filter) != '\0' )
        tag_ptr->filter = expr4parse( d4, tag_data[i].filter ) ;

    if ( c4->error_code < 0 )
      break ;
    l4add( &i4->tags, tag_ptr ) ;
  }

#ifdef S4DEBUG
  if ( i4->header.num_tags > 47 )
    e4severe( e4parm, E4_PARM_TOO ) ;
#endif
#endif

  rc = i4reindex( i4 ) ;

  if ( rc == r4unique || rc < 0 )
  {
    c4->error_code = r4unique ;
    i4close( i4 ) ;
    return 0 ;
  }

  if ( file_name == 0 )
  {
    d4->has_mdx = 1 ;

    file4write( &d4->file, ( 4 + ( sizeof(S4LONG) ) + 2 * ( sizeof( short ) ) + ( sizeof( char[16] ) ) ),
               &i4->data->has_mdx, sizeof( i4->data->has_mdx ) ) ;
  }
  if ( c4->error_code < 0 || c4->error_code == r4unique )
  {
    i4close( i4 ) ;
    return 0 ;
  }
#ifndef S4OPTIMIZE_OFF
  file4optimize( &i4->file, c4->optimize, OPT4INDEX ) ;
  if ( has_opt )
    d4opt_restart( c4 ) ;
#endif  /* not S4OPTIMIZE_OFF */
  return i4 ;
}

#endif   /*  ifndef N4OTHER  */

#ifdef N4OTHER

INDEX4 *S4FUNCTION i4create( DATA4 *d4, char *file_name, TAG4INFO *tag_data )
{
  INDEX4 *i4 ;
  CODE4 *c4 ;
  char buf[258] ;
  int i, rc ;
#ifdef S4OLD_CODE
  int len, num_files ;
  long pos ;
#else
  char buffer[1024] ;
  FILE4SEQ_WRITE seqwrite ;
#endif

#ifdef S4VBASIC
  if ( c4parm_check( d4, 2, E4_I4CREATE ) )
    return 0 ;
#endif

#ifdef S4DEBUG
  if ( d4 == 0 || tag_data == 0 )
    e4severe( e4parm, E4_I4CREATE ) ;

  if ( file_name )
    u4name_piece( buf, sizeof( buf ), file_name, 0, 0 ) ;
  else
    u4name_piece( buf, sizeof( buf ), d4->file.name, 0, 0 ) ;
  if ( d4index( d4, buf ) )
  {
    e4( d4->code_base, e4info, E4_INFO_IAO ) ;
    return 0 ;
  }
#endif

  c4 = d4->code_base ;
  if ( c4->error_code < 0 )
    return 0 ;
  c4->error_code = 0 ;  /* Make sure it is not 'r4unique' or 'r4no_create'. */

#ifndef S4SINGLE
  if ( d4lock_file( d4 ) )
    return 0 ;
#endif

  i4 = (INDEX4 *)mem4create_alloc( c4, &c4->index_memory, c4->mem_start_index, sizeof(INDEX4), c4->mem_expand_index, 0 ) ;

  if ( i4 == 0 )
  {
    e4( c4, e4memory, 0 ) ;
    return 0 ;
  }

  i4->code_base = c4 ;
  i4->data = d4 ;

  memset( buf, 0, sizeof( buf ) ) ;

  if ( file_name )  /* create a group file */
  {
    u4ncpy( buf, file_name, sizeof( buf ) ) ;
    u4ncpy( i4->alias, buf, sizeof( i4->alias ) ) ;
    c4trim_n( i4->alias, sizeof( i4->alias ) ) ;
#ifndef S4UNIX
    c4upper( i4->alias ) ;
#endif

    u4name_ext( buf, sizeof( buf ), "CGP", 1 ) ;
#ifndef S4UNIX
    c4upper( buf ) ;
#endif

    rc = file4create( &i4->file, c4, buf, 1 ) ;
    if ( rc )
    {
      if ( rc > 0 )
        c4->error_code = rc ;

      file4close( &i4->file ) ;
      return 0 ;
    }

#ifdef S4OLD_CODE
    /* calculate # of files */
    for ( num_files = 0; tag_data[num_files].name; num_files++ ) ;

    pos = 0L ;
    file4write( &i4->file, pos, &num_files, sizeof( num_files ) ) ;
    pos += sizeof( num_files ) ;

    /* create the group file */
    for ( i = 0; tag_data[i].name; i++ )
    {
      len = strlen( tag_data[i].name ) ;
      file4write( &i4->file, pos, &len, sizeof( len ) ) ;
      pos += sizeof( len ) ;
      file4write( &i4->file, pos, tag_data[i].name, len ) ;
      pos += len ;
    }
#else
    file4seq_write_init( &seqwrite, &i4->file, 0L, buffer, sizeof( buffer ) ) ;

    /* create the group file */
    for ( i = 0; tag_data[i].name; i++ )
    {
      file4seq_write( &seqwrite, tag_data[i].name, strlen( tag_data[i].name ) ) ;
      file4seq_write( &seqwrite, "\r\n", 2 ) ;
    }

    file4seq_write_flush( &seqwrite ) ;
#endif

    file4close ( &i4->file ) ;

#ifndef S4SINGLE
    if ( rc )
    {
      if ( rc > 0 )
        c4->error_code = rc ;
      return 0 ;
    }
#endif
    i4->path = buf ;
  }

  l4add( &d4->indexes, i4 ) ;

  /* now create the actual tag files */
  for ( i = 0 ; tag_data[i].name ; i++ )
    if( t4create( d4, &tag_data[i], i4 ) == 0 )
    {
      i4close( i4 ) ;
      return 0 ;
    }

  if ( c4->error_code < 0 || c4->error_code == r4unique )
  {
    i4close( i4 ) ;
    return 0 ;
  }

  if ( i4reindex( i4 ) == r4unique )
  {
    i4close( i4 ) ;
    return 0 ;
  }

  return i4 ;
}

/* this function does not reindex if an 'i4ndx' is passed as a parameter */
/* this allows several creations before an actual reindex must occur */
TAG4 *S4FUNCTION t4create( DATA4 *d4, TAG4INFO *tag_data, INDEX4 *i4ndx )
{
  CODE4  *c4 ;
  INDEX4 *i4 ;
  char   buf[258] ;
  TAG4 *t4 ;
  int rc ;
#ifndef S4OPTIMIZE_OFF
  int has_opt ;
#endif
#ifdef S4DEBUG
  int old_tag_err ;
#endif

#ifdef S4VBASIC
  if ( c4parm_check( d4, 2, E4_T4CREATE ) )
    return 0 ;
#endif

#ifdef S4DEBUG
  if ( d4 == 0 || tag_data == 0 )
    e4severe( e4parm, E4_T4CREATE ) ;
#ifdef S4NDX
  if( ( tag_data->filter != 0 && *tag_data->filter != '\0' ) || tag_data->descending != 0 )
    e4severe( e4parm, E4_PARM_FOR ) ;
#endif

  u4name_piece( buf, sizeof( buf ), tag_data->name, 0, 0 ) ;

  if ( d4->code_base->error_code < 0 )
    return 0 ;

  old_tag_err = d4->code_base->tag_name_error ;
  d4->code_base->tag_name_error = 0 ;
  if ( d4tag( d4, buf ) )
  {
    e4( d4->code_base, e4info, E4_INFO_TAO ) ;
    d4->code_base->tag_name_error = old_tag_err ;
    return 0 ;
  }
  d4->code_base->tag_name_error = old_tag_err ;
  d4->code_base->error_code = 0 ;
#endif

  c4 = d4->code_base ;
  if ( c4->error_code < 0 )
    return 0 ;
  c4->error_code = 0 ;  /* Make sure it is not 'r4unique' or 'r4no_create'. */

#ifndef S4OPTIMIZE_OFF
  if ( c4->has_opt )
  {
    has_opt = 1 ;
    d4opt_suspend( c4 ) ;
  }
  else
    has_opt = 0 ;
#endif  /* not S4OPTIMIZE_OFF */

  if ( i4ndx == 0 )   /* must create an index for the tag */
  {
    if ( c4->index_memory == 0 )
      c4->index_memory = mem4create( c4, c4->mem_start_index, sizeof(INDEX4),
                                    c4->mem_expand_index, 0 ) ;
    if ( c4->index_memory == 0 )
      return 0 ;
    i4 = (INDEX4 *) mem4alloc( c4->index_memory ) ;
    if ( i4 == 0 )
    {
      e4( c4, e4memory, 0 ) ;
      return 0 ;
    }
    i4->data = d4 ;
    i4->code_base = c4 ;
#ifdef S4DEBUG
    u4name_piece( buf, sizeof( buf ), i4->alias, 0, 0 ) ;
    if ( d4index( d4, buf ) )
    {
      e4( d4->code_base, e4info, E4_INFO_IAO ) ;
      return 0 ;
    }
#endif
    u4name_piece( i4->alias, sizeof( i4->alias ), tag_data->name, 0, 0 ) ;
  }
  else
    i4 = i4ndx ;

  if ( c4->tag_memory == 0 )
  {
    c4->tag_memory = mem4create( c4, c4->mem_start_tag, sizeof(TAG4),
                                c4->mem_expand_tag, 0 ) ;
    if ( c4->tag_memory == 0 )
      return 0 ;
  }

  t4 = (TAG4 *) mem4alloc( c4->tag_memory ) ;
  if ( t4 == 0 )
  {
    e4( c4, e4memory, 0 ) ;
    return 0 ;
  }

  if ( i4->block_memory == 0 )
    i4->block_memory = mem4create( c4, c4->mem_start_block,
                                  sizeof(B4BLOCK) + B4BLOCK_SIZE -
                                  (sizeof(B4KEY_DATA)) - (sizeof(short)) - (sizeof(char[2])),
                                  c4->mem_expand_block, 0 ) ;

  if ( i4->block_memory == 0 )
  {
    mem4free( c4->tag_memory, t4 ) ;
    return 0 ;
  }

  if ( i4ndx != 0 && i4->path != 0)
  {
    rc = u4name_path( buf, sizeof(buf), i4ndx->path ) ;
    u4ncpy( buf+rc, tag_data->name, sizeof(buf)-rc ) ;
  }
  else
    u4ncpy( buf, tag_data->name, sizeof(buf) ) ;

#ifndef S4UNIX
  c4upper(buf) ;
#endif

#ifdef S4NDX
#ifdef S4UNIX
  u4name_ext( buf, sizeof(buf), "ndx", 0 ) ;
#else
  u4name_ext( buf, sizeof(buf), "NDX", 0 ) ;
#endif
#else
#ifdef S4CLIPPER
#ifdef S4UNIX
  u4name_ext( buf, sizeof(buf), "ntx", 0 ) ;
#else
  u4name_ext( buf, sizeof(buf), "NTX", 0 ) ;
#endif
#endif
#endif

  u4name_piece( t4->alias, sizeof( t4->alias ), tag_data->name, 0, 0 ) ;
#ifndef S4UNIX
  c4upper( t4->alias ) ;
#endif

  rc = file4create( &t4->file, c4, buf, 1 ) ;
  if ( rc )
  {
    mem4free( c4->tag_memory, t4 ) ;
    return 0 ;
  }

  if ( tag_data->unique )
  {
#ifdef S4NDX
    t4->header.unique     = 0x4000 ;
#else
#ifdef S4CLIPPER
    t4->header.unique     = 0x01 ;
#endif
#endif

    t4->unique_error = tag_data->unique ;

#ifdef S4DEBUG
    if ( tag_data->unique != e4unique &&
        tag_data->unique != r4unique &&
        tag_data->unique != r4unique_continue )
      e4severe( e4parm, E4_PARM_UNI ) ;
#endif
  }

#ifdef S4CLIPPER
  if ( tag_data->descending)
  {
    t4->header.descending = 1 ;
#ifdef S4DEBUG
    if ( tag_data->descending != r4descending )
      e4severe( e4parm, E4_PARM_FLA ) ;
#endif
  }
#endif

#ifdef S4DEBUG
  if ( tag_data->expression == 0 )
    e4severe( e4parm, E4_PARM_TAG ) ;
#endif

  t4->expr = expr4parse( d4, tag_data->expression ) ;
  if ( t4->expr == 0 )
  {
    mem4free( c4->tag_memory, t4 ) ;
    return 0 ;
  }

#ifdef S4CLIPPER
  if ( tag_data->filter != 0 )
    if ( *( tag_data->filter ) != '\0' )
      t4->filter = expr4parse( d4, tag_data->filter ) ;
#endif

#ifdef S4NDX
  t4->header.eof = 2 ;
  t4->header.root = 1 ;
#else
#ifdef S4CLIPPER
  t4->header.eof = 0 ;
  t4->header.root = 1024 ;
  t4->header.key_len = c4->numeric_str_len ;
  t4->header.key_dec = c4->decimals ;
  if( t4->expr->type == r4num )
  {
    t4->header.key_len = t4->expr->key_len ;
    t4->header.key_dec = t4->expr->key_dec ;
  }
#endif
#endif

  if ( c4->error_code < 0 )
  {
    mem4free( c4->tag_memory, t4 ) ;
    return 0 ;
  }

  t4->code_base = c4 ;
  t4->index = i4 ;

  /* add the tag to the index list */
  l4add( &i4->tags, t4 ) ;

  if ( i4ndx == 0 )   /* single create, so reindex now */
  {
    if ( t4reindex( t4 ) == r4unique )
    {
      c4->error_code = r4unique ;
      mem4free( c4->tag_memory, t4 ) ;
      return 0 ;
    }

    l4add( &i4->data->indexes, i4 ) ;
  }

#ifndef S4OPTIMIZE_OFF
  file4optimize( &t4->file, c4->optimize, OPT4INDEX ) ;
  if ( has_opt )
    d4opt_restart( c4 ) ;
#endif
  return t4 ;
}
#endif   /* N4OTHER */

#endif   /* S4OFF_WRITE */
#endif   /* S4OFF_INDEX */

#ifdef S4VB_DOS

INDEX4 * i4create_v ( DATA4  *d4, char near *name, TAG4INFO *t4 )
{
  return i4create( d4, c4str(name), t4 ) ;
}

INDEX4 * i4createProd ( DATA4  *d4, TAG4INFO *t4 )
{
  return i4create( d4, 0, t4 ) ;
}

#endif
