
#include "p.basic.h"

@begin
   header "basic.h";
@end

/*
 * structure implementing memory control, at the begin of program must be called function
 * mc_init() and at the end of the program must be called function mc_clear().
 * to allocation and deallocation of memory use cmalloc() and cfree()
 */
#ifdef MEM_CHECK

// --- function of structure mce_struct_s ---

/*
 * check if every allocated block of memory has been deallocated
 * if exist some not deallocated memory block, function prints debug message
 */
void mce_struct_s::check(bool silent)
{
   if (data_start == c_idx_not_exist) {
      return;
   }

   // - silent clear of unallocated memory -
   if (silent) {
      unsigned idx = data_start;
      do {
	 mce_block_s &block = data[idx];

	 free(block.location);

	 idx = block.next_idx;
      } while(idx != c_idx_not_exist);
   }

   // - clear of unallocated memory with message about every block -
   else {
      unsigned idx = data_start;
      do {
	 mce_block_s &block = data[idx];

	 fprintf(stderr,"MEM_CHECK_ENCHANCED: leak at: %d, size: %d\n",(unsigned)block.location,block.size);
	 free(block.location);

	 idx = block.next_idx;
      } while(idx != c_idx_not_exist);
   }
}

/*
 * change of size of array used to store records about allocated memory
 */
void mce_struct_s::copy_resize(unsigned a_size)
{
   debug_assert(a_size >= size);

   if (a_size == size) {
      return;
   }

   mce_block_s *n_data = (mce_block_s *)malloc(a_size*sizeof(mce_block_s));

   if (size != 0) {
      memcpy(n_data,data,size*sizeof(mce_block_s));
      free(data);
   }

   unsigned idx = size;
   unsigned idx_end = a_size - 1;

   if (idx < idx_end) {
      do {
	 n_data[idx].next_idx = idx + 1;
      } while(++idx < idx_end);
   }

   n_data[idx].next_idx = empty_start;
   empty_start = size;

   data = n_data;
   size = a_size;
}

/*
 * allocate new block of memory, which is saved to structure,
 * and then return pointer on that block
 */
void *mce_struct_s::create_block(unsigned a_size)
{
   void *location = malloc(a_size);

   if (empty_start == c_idx_not_exist) {
      copy_resize(size + c_array_add);
   }

   unsigned old_empty_start = empty_start;
   mce_block_s &block = data[old_empty_start];

   empty_start = block.next_idx;
   block.next_idx = data_start;
   data_start = old_empty_start;

   block.location = location;
   block.size = a_size;

   return location;
}

/*
 * check if block of memory is allocated and then free it
 */
void mce_struct_s::delete_block(void *a_location)
{
   debug_assert(data_start != c_idx_not_exist);

   unsigned idx = data_start;
   unsigned old_idx = c_idx_not_exist;
   do {
      mce_block_s &block = data[idx];

      if (block.location == a_location) {
	 break;
      }

      old_idx = idx;
      idx = block.next_idx;

   } while(idx != c_idx_not_exist);

   debug_assert(idx != c_idx_not_exist);

   mce_block_s &block = data[idx];

   if (old_idx == c_idx_not_exist) {
      data_start = block.next_idx;
   }
   else {
      data[old_idx].next_idx = block.next_idx;
   }

   block.next_idx = empty_start;
   empty_start = idx;

   free(block.location);
}

/*
 * instance of memory control structure
 */

mce_struct_s mce;

#endif

/*
 * function which prints information about errors
 */

#ifdef ERR_MSGS

void err_message(unsigned a_type,unsigned *parm_list)
{
   switch (a_type) {
   case c_ERR_NOT_ENOUGH_CL_PARAMETERS:
      fprintf(stderr,"Error: Not enough command line parameters.\nUsage: program <script_file> <script_parameters> ...\n");
      break;
   case c_ERR_CANNOT_OPEN_SOURCE_FILE:
      fprintf(stderr,"Error: Cannot open script source file \"%s\".\n",(char *)parm_list[0]);
      break;
   case c_DP_ERR_FUN_NAME_EXCEED_MAX_SIZE:
      fprintf(stderr,"Error: %u: %s name \"%s\" with parameters, exceed max name size.\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2]);
      break;
   case c_DP_UNIMPLEMENTED_CONST_NOTATION:
      fprintf(stderr,"Error: %u: Unimplemented %s constant notation.\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_P_ERR_IDENTIFIER_ALREADY_EXIST:
      fprintf(stderr,"Error: %u: %s identifier \"%s\", is already used.\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2]);
      break;
   case c_P_ERR_CONTINUE_BREAK_OUTSIDE_OF_LOOP:
      fprintf(stderr,"Error: %u: Keyword %s used outside of a loop.\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_P_ERR_RETURN_OUTSIDE_OF_FUNCTION:
      fprintf(stderr,"Error: %u: Keyword return used outside of a function.\n",parm_list[0]);
      break;
   case c_P_ERR_X_NOT_DEFINED:
      fprintf(stderr,"Error: %u: %s \"%s\" is not defined.\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2]);
      break;
   case c_P_ERR_WRONG_ESCAPE_CODE:
      fprintf(stderr,"Error: %u: Wrong escape code \'%c\', in %s.\n",parm_list[0],(char)parm_list[1],(char *)parm_list[2]);
      break;
   case c_P_ERR_UNRECOGNIZABLE_TERMINAL:
      fprintf(stderr,"Error: %u: Unrecognizable input terminal: \"%s\".\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_P_ERR_WRONG_PROGRAM_SYNTAX:
      fprintf(stderr,"Error: %u: Wrong program syntax at \"%s\".\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_DR_ERR_MUTEXT_OPERATION_UNIMPLEMENTED:
      fprintf(stderr,"Error: Mutex operation \"%s\", is not implemented.\n",(char *)parm_list[0]);
      break;
   case c_DR_ERR_MUTEX_OPERATION_FAILED:
      fprintf(stderr,"Error: Mutex operation \"%s\", has failed.\n",(char *)parm_list[0]);
      break;
   case c_DR_ERR_OPERATION_NOT_IMPLEMENTED:
      fprintf(stderr,"Error: %u: Debug: Operation \"%s\", is not implemented, but parsed.\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_DR_ERR_EXCEED_MAX_STRING_SIZE:
      fprintf(stderr,"Error: %u: conversion from \"%s\" to \"string_s\" exceed build_in limit.\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_R_ERR_LOAD_BUFFER_OVERFLOW:
      fprintf(stderr,"Error: Load buffer overflow (wrong file or data structure).\n");
      break;
   case c_R_ERR_EXPECTED_NUMBER_EXPRESSION:
      fprintf(stderr,"Error: %u: In \"%s\" is expected number expression.\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_R_ERR_STRUCT_X_NOT_DEFINED:
      fprintf(stderr,"Error: %u: %s \"%s\" of structure \"%s\" is not defined.\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2],(char *)parm_list[3]);
      break;
   case c_R_ERR_CANNOT_CREATE_THIS_OBJECT:
      fprintf(stderr,"Error: %u: Cannot create object of type \"%s\".\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_R_ERR_NOT_ALLOWED_MULTITHREADING:
      fprintf(stderr,"Error: %u: Multithreading is not allowed.\n",parm_list[0]);
      break;
   case c_R_ERR_NOT_COMPATIBLE_ARRAY_ELEMENT:
      fprintf(stderr,"Error: %u: Not compatible \"%s\" array and \"%s\" element.\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2]);
      break;
   case c_R_ERR_WRONG_PARAM_EXPECTED_PARAM:
      fprintf(stderr,"Error: %u: Wrong parameter of operation \"%s\", expected \"%s\", obtained \"%s\".\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2],(char *)parm_list[3]);
      break;
   case c_R_ERR_UNKNOWN_X_OPERATION_CONSTANT:
      fprintf(stderr,"Error: %u: Unknown constant code %u of operation \"%s\".\n",parm_list[0],parm_list[1],(char *)parm_list[2]);
      break;
   case c_R_ERR_EXPECTED_WRITABLE:
      fprintf(stderr,"Error: %u: On left side is expected writable (not constant) object in \"%s\".\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_R_ERR_WRONG_PARAMETER:
      fprintf(stderr,"Error: %u: Wrong parameter \"%s\" of operation \"\%s\".\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2]);
      break;
   case c_R_ERR_CANNOT_ASSING_TO_INDEXED:
      fprintf(stderr,"Error: %u: Cannot assign \"%s\" to indexed \"%s\", in operation \"%s\".\n",parm_list[0],(char *)parm_list[1],(char *)parm_list[2],(char *)parm_list[3]);
      break;
   case c_R_ERR_IDX_EXCEED_ARRAY_STRING_SIZE:
      fprintf(stderr,"Error: %u: Index exceed \"%s\" size.\n",parm_list[0],(char *)parm_list[1]);
      break;
   case c_R_ERR_LOCKED_MUTEX_DESTROY:
      fprintf(stderr,"Error: Trying to destroy locked mutex.\n");
      break;
   case c_R_ERR_USED_CONDITION_DESTROY:
      fprintf(stderr,"Error: Trying to destroy used condition.\n");
      break;
   case c_R_ERR_THREAD_FUNCTION_RETURN:
      fprintf(stderr,"Error: %u: Wrong thread function return value.\n",parm_list[0]);
      break;
   case c_R_ERR_IMAGE_OPERATION_RETURN:
      fprintf(stderr,"Error: %u: Image operation \"%s\" failed for some reason.\n",parm_list[0],(char *)parm_list[1]);
      break;
   default:
      assert(0);
   }
}

#endif


