view urogue/dictutil.c @ 295:1e1c81fbb533

Rogue V5: fix elemental wands. Bolts often failed to hit, due to some struct members not being initialized. Reported by 'LazyCat' from RogueTemple.
author John "Elwin" Edwards
date Fri, 12 Jan 2018 18:02:39 -0500
parents c4b12d2d1dcd
children 13b482bd9e66
line wrap: on
line source

/*
    dictutil.c

    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
    Copyright (C) 1995 Herb Chong
    All rights reserved.

    See the file LICENSE.TXT for full copyright and licensing information.
*/

/*************************************************************************
**   Utilities for Dictionary Maintenence Functions
*************************************************************************/

static char sccsid[] = "%W% %G%";

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if !defined(OS2) && !defined(_WIN32)
   #include <unistd.h>
#else
   #include <io.h>
   #include <fcntl.h>
#endif

#include "dict.h"
#include "dictutil.h"
#include "rogue.h"

int   dict_trace;
FILE  *ft;


/***********
**  Read 'count' characters into 'buffer' at 'offset' in a binary file
**  Return 0 on success; -1 on failure;
***********/

int block_read( FILE *fi , char *buffer , size_t count , long offset )
{
   if ( fseek(fi,offset,SEEK_SET) == -1 )
      return( -1 );

   if ( fread(buffer,1,count,fi) != count )
      return( -1 );
   return( 0 );
}

/***********
**  Write 'count' characters from 'buffer' to a binary file.
**  Return -1 on failure; 0 on success.
***********/

int block_write( FILE *fo , char *buffer , size_t count )
{
   if ( fwrite(buffer,1,count,fo) != count )
      return( -1 );
   return( 0 );
}

/***********
**  Load a dictionary table entry with id TOC_id into memory pointed to by block.
**  Update the dictionary TOC.
**  If *block=NULL, allocate the block of memory.
**  Return 0 on success; -1 on failure.
**  Set dt_entry->ptr to where the block is stored.
***********/

void *dict_load_block( DICTIONARY *dict , char *toc_id ,
                          FILE *fi , void *block )
{  DICT_TOC_ENTRY  *dt_entry;
   static void     *ptr;
   int             index, ret_code;

   index = dict_toc_index( dict , toc_id );
   if ( index != -1 ) {  /* Found the id */
      dt_entry = &(dict->toc[index]);
   } else {
      signal_error( "dict_load_block: could not find TOC_id" , toc_id , 1 );
      return( NULL );
   } /* endif */

   if ( block == NULL ) {
      ptr = malloc( dt_entry->size );
      if ( dict_trace > 3 ) {
         fprintf( ft , "\ndict_load_block allocates %lx bytes at location %p\n" ,
                   dt_entry->size , ptr );
      } /* endif */
   } else {
      ptr = block;
      if ( dict_trace > 3 ) {
         fprintf( ft , "\ndict_load_block uses memory at location %p\n" , ptr );
      } /* endif */
   } /* endif */
   if ( ptr == NULL ) {
      signal_error( "dict_load_block: alloc failed " , toc_id , 1 );
      return( NULL );
   } /* endif */

   ret_code = block_read( fi ,
                          (char*)ptr ,
                          dt_entry->size ,
                          dt_entry->offset );
   if ( ret_code == -1 )
      return( NULL );

   if ( dt_entry->checksum !=
        compute_checksum( dt_entry->size , (char*)ptr ) ) {
      signal_error( "dict_load_block: invalid checksum ", toc_id, 1);
      return( NULL );
   } /* endif */

   dt_entry->ptr = ptr;

   if ( dict_trace > 3 ) {
      fprintf( ft , "\nLoaded block\nTOC entry:    id:%s  offset:%lx  size:%lx  ptr:%p  checksum:%lx  type:%d\n" ,
               dict->toc[index].id , dict->toc[index].offset ,
               dict->toc[index].size , dict->toc[index].ptr ,
               dict->toc[index].checksum , dict->toc[index].type );
   } /* endif */

   return( ptr );
}

/***********
**  Save a dictionary table entry.
**  Update the dictionary TOC entry offset and checksum fields.
**  Return 0 on success, -1 on failure.
**  Note: It is assumed that the size and pointer fields in TOC entry are
**        already up to date; i.e., that they are consistent with the current
**        location and size of the block being written. This is essential
**        because the table of contents must have already been written
**        into the file.
***********/

BOOLEANC dict_save_block( DICTIONARY *dict , char *toc_id , FILE *fo )
{  DICT_TOC_ENTRY   *dt_entry;
   int              index, ret_code;
   char             *block;

   index = dict_toc_index( dict , toc_id );
   if ( index == -1 ) {
      signal_error( "dict_save_block: id not found " , toc_id , 1 );
      return( FALSE );
   } /* endif */
   dt_entry = &(dict->toc[index]);
   block = (char*)(dt_entry->ptr);

   if ( block == NULL ) {
      signal_error( "dict_save_block: NULL block " , toc_id , 1 );
      return( FALSE );
   } /* endif */

   /* dt_entry->offset = fseek( fo , 0 , SEEK_END ); */
   dt_entry->checksum = compute_checksum( dt_entry->size , block );
   ret_code = block_write( fo , dt_entry->ptr , dt_entry->size );
   if ( ret_code == -1 ) {
      signal_error( "dict_save_block: block_write failed " , toc_id , 1 );
      return( FALSE );
   } /* endif */

   if ( dict_trace > 3 ) {
      fprintf( ft , "\nStored block\nTOC entry:           id:%s  offset:%lx  size:%lx  ptr:%p  checksum:%lx  type:%d\n" ,
               dict->toc[index].id , dict->toc[index].offset ,
               dict->toc[index].size , dict->toc[index].ptr ,
               dict->toc[index].checksum , dict->toc[index].type );
   } /* endif */

   return( TRUE );
}

/***********
**  Look up and id in the table of contents.
**  Return its index (-1 on failure).
***********/

int dict_toc_index( DICTIONARY *dict , char *toc_id )
{  int index;

   for ( index = 0 ; index < dict->sig->toc_size ; index++ ) {
           if ( strcmp(dict->toc[index].id,toc_id) == 0 )
                   return( index );
   } /* endfor */

   return( -1 );
}

/***********
**  Compute a block checksum.
**  (Currently just returns 0.)
***********/

unsigned long compute_checksum( size_t size , char *block )
{
    NOOP(size);
    NOOP(block);
    return( 0 );
}

/***********
**  Create a dictionary paramter entry.
***********/

DICT_PARM_ENTRY *dict_make_parm_entry( char *id , unsigned long value )
{  static DICT_PARM_ENTRY  *entry;

   entry = (DICT_PARM_ENTRY *) malloc( sizeof(DICT_PARM_ENTRY) );
   if ( entry == NULL )
      return(NULL);

   strncpy( entry->id , id , 13 );
   entry->value = value;

   return( entry );
}

/***********
**  Look up and id in the parameter array.
**  Return its index (-1 on failure).
***********/

int dict_parm_index( DICTIONARY *dict , char *parm_id )
{  long index;

   for ( index = 0 ; index < dict->sig->nparms ; index++ ) {
           if ( strcmp( dict->parm[index].id , parm_id ) == 0 )
                   return( (int) index );
   } /* endfor */

   return( -1 );
}

/***********
**  Reset table of contents offsets and checksums
**  in preparation for dict_save().
***********/

BOOLEANC dict_reset_toc_offsets( DICTIONARY *dict )
{  int  i;
   long offset;

   offset = sizeof(DICT_SIG)
          + dict->sig->toc_size * sizeof(DICT_TOC_ENTRY);
   for ( i = 0 ; i < dict->sig->toc_size ; i++ ) {
      dict->toc[i].offset = offset;
      offset += dict->toc[i].size;
      dict->toc[i].checksum =
         compute_checksum( dict->toc[i].size , dict->toc[i].ptr );
   } /* endfor */

   return( TRUE );
}

/***********
**  Load the names of the dictionary parameters.
**  14 parms
***********/

BOOLEANC dict_set_parm_ids( DICTIONARY *dict )
{
   if ( dict==NULL || dict->sig == NULL ) {
      signal_error( "dict_set_parm_ids: Allocate dict and signature first." , "" , 0 );
      return( FALSE );
   }
   dict->sig->nparms = 14;
   strcpy( dict->parm[0].id , "FLAGS_______" );
   strcpy( dict->parm[1].id , "ENTRY_COUNT_" );
   strcpy( dict->parm[2].id , "ARRAY_SIZE__" );
   strcpy( dict->parm[3].id , "ARRAY_USED__" );
   strcpy( dict->parm[4].id , "ARR_GROW_CT_" );
   strcpy( dict->parm[5].id , "STRING_MAX__" );
   strcpy( dict->parm[6].id , "STR_GROW_CT_" );
   strcpy( dict->parm[7].id , "LONG_CHAIN__" );
   strcpy( dict->parm[8].id , "ALLOW_CHAIN_" );
   strcpy( dict->parm[9].id , "HASH_TAB_SIZ" );
   strcpy( dict->parm[10].id , "HASH_MASK___" );
   strcpy( dict->parm[11].id , "HASH_GROW_CT" );
   strcpy( dict->parm[12].id , "CHECK_VALUE_" );
   strcpy( dict->parm[13].id , "SCAN_STR_IX_" );

   return( TRUE );
}

/***********
**  Set the dictionary parm structure from the values in the dict structure.
**  14 parms
***********/

BOOLEANC dict_set_parm_values( DICTIONARY *dict )
{  int  index;

   if ( (index=dict_parm_index(dict,"FLAGS_______")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->flags;

   if ( (index=dict_parm_index(dict,"ENTRY_COUNT_")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->entry_count;

   if ( (index=dict_parm_index(dict,"ARRAY_SIZE__")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->array_size;

   if ( (index=dict_parm_index(dict,"ARRAY_USED__")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->array_used;

   if ( (index=dict_parm_index(dict,"ARR_GROW_CT_")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->array_growth_count;

   if ( (index=dict_parm_index(dict,"STRING_MAX__")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->string_max;

   if ( (index=dict_parm_index(dict,"STR_GROW_CT_")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->string_growth_count;

   if ( (index=dict_parm_index(dict,"LONG_CHAIN__")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->longest_chain_length;

   if ( (index=dict_parm_index(dict,"ALLOW_CHAIN_")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->allowable_chain_length;

   if ( (index=dict_parm_index(dict,"HASH_TAB_SIZ")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->table_size;

   if ( (index=dict_parm_index(dict,"HASH_MASK___")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->hash_mask;

   if ( (index=dict_parm_index(dict,"HASH_GROW_CT")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->hash_growth_count;

   if ( (index=dict_parm_index(dict,"CHECK_VALUE_")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->check_value;

   if ( (index=dict_parm_index(dict,"SCAN_STR_IX_")) == -1 )
      return( FALSE );
   dict->parm[index].value = (unsigned long)dict->scan_string_index;

   return( TRUE );
}


/***********
**  Set the values in the dict structure from the dictionary parm structure.
**  14 parms
***********/

BOOLEANC dict_set_parm_variables( DICTIONARY *dict )
{  int  index;

   if ( (index=dict_parm_index(dict,"FLAGS_______")) == -1 )
      return( FALSE );
   dict->flags = (unsigned long)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"ENTRY_COUNT_")) == -1 )
      return( FALSE );
   dict->entry_count = (long)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"ARRAY_SIZE__")) == -1 )
      return( FALSE );
   dict->array_size = (long)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"ARRAY_USED__")) == -1 )
      return( FALSE );
   dict->array_used = (long)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"ARR_GROW_CT_")) == -1 )
      return( FALSE );
   dict->array_growth_count = (int)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"STRING_MAX__")) == -1 )
      return( FALSE );
   dict->string_max = (long)dict->parm[index].value ;

   if ( (index=dict_parm_index(dict,"STR_GROW_CT_")) == -1 )
      return( FALSE );
   dict->string_growth_count = (int)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"LONG_CHAIN__")) == -1 )
      return( FALSE );
   dict->longest_chain_length = (int)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"ALLOW_CHAIN_")) == -1 )
      return( FALSE );
   dict->allowable_chain_length = (int)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"HASH_TAB_SIZ")) == -1 )
      return( FALSE );
   dict->table_size = (long)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"HASH_MASK___")) == -1 )
      return( FALSE );
   dict->hash_mask = (unsigned long)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"HASH_GROW_CT")) == -1 )
      return( FALSE );
   dict->hash_growth_count = (int)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"CHECK_VALUE_")) == -1 )
      return( FALSE );
   dict->check_value = (unsigned long)dict->parm[index].value;

   if ( (index=dict_parm_index(dict,"SCAN_STR_IX_")) == -1 )
      return( FALSE );
   dict->scan_string_index = (long)dict->parm[index].value;

   return( TRUE );
}

/***********
**  If dict_trace (global) > 0 , signal an error
**  If severity > 0 , abort
***********/

void signal_error( char *header , char *message , int severity )
{
  FILE *fpe;

  if ( dict_trace > 0 ) {
     printf( "%s: %s\n" , header , message );
     fpe = fopen( "ERROR.FIL" , "a" );
     fprintf( fpe , "\n%s: %s\n" , header , message );
     fclose( fpe );
  } /* endif */

  if ( severity > 0 )
     abort();
}