Esempio n. 1
0
/** \brief pack bit states in byte buffer
 *  \param[in] number of pins to read (normally ciaaDriverDio_OutputCount or ciaaDriverDio_InputCount)
 *  \param[out] buffer user buffer
 *  \param[in] size user buffer size
 *  \param[in] readFunction function used to read pins (normally ciaa_lpc4337_readOutput or ciaa_lpc4337_readInput)
 *  \return number bytes required in buffer to store bits
 */
static int32_t ciaa_lpc4337_readPins(int32_t pinCount, uint8_t * buffer, size_t size, int32_t (*readFunction)(uint32_t))
{
   int32_t count, i, j;
   /* amount of bytes necessary to store all input states */
   count = pinCount >> 3; /* ciaaDriverDio_InputCount / 8 */
   if( (pinCount & 0x07) != 0) /* (ciaaDriverDio_InputCount % 8) != 0 */
   {
      count += 1;
   }
   /* adjust gpios to read according to provided buffer length */
   if(count > size)
   {
      count = size;
   }
   /* read and store all inputs in user buffer */
   ciaaPOSIX_memset(buffer, 0, count);
   for(i = 0, j = 0; (i < pinCount) && (j < count); i++)
   {
      if((i > 0) && ((i & 0x07)==0))
      {
         j++;
      }
      buffer[j] |= readFunction(i) << (i - 8 * j);
   }
   return count;
}
Esempio n. 2
0
bool VrmlScene::loadFromFunction( LoadCB cb, const char *url )
{
  Doc *doc = url ? new Doc( url, 0 ) : 0;
  VrmlNamespace *ns = new VrmlNamespace();
  VrmlMFNode *newNodes = readFunction( cb, doc, ns );

  if ( newNodes )
    {
      replaceWorld( *newNodes, ns, doc, 0 );
      delete newNodes;
      return true;
    }
  if (doc) delete doc;
  return false;
}
Esempio n. 3
0
void numberToFunction(int number, char* secondary){
	if (number == 1){
		readFunction(secondary);
	}
	else if (number == 2){
		writeFunction(secondary);
	}
	else if (number == 3){
		deleteFunction(secondary);
	}
	else if (number == 4){
		printFunction();
	}
	else if (number == 0){
		printf("Not a valid command!\n");
	}
	else if (number == 404){
		printf("The file you provided does not exist.\n");
	}
}
bool Origin410Parser::parse()
{
	unsigned int dataIndex = 0;

#ifndef NO_LOG_FILE
	// append progress in log file
	logfile = fopen("opjfile.log", "a");
#endif

	/////////////////// find column ///////////////////////////////////////////////////////////
	skipLine();
	unsigned int size;
	file >> size;
	file.seekg(1 + size + 1 + 5, ios_base::cur);

	file >> size;
	file.seekg(1, ios_base::cur);
	LOG_PRINT(logfile, "	[column found = %d/0x%X @ 0x%X]\n", size, size, (unsigned int) file.tellg());

	unsigned int colpos = file.tellg();
	unsigned int current_col = 1, nr = 0, nbytes = 0;

	while(size > 0 && size <= 0x8B){// should be 0x72, 0x73 or 0x83 ?
		//////////////////////////////// COLUMN HEADER /////////////////////////////////////////////

		short data_type;
		char data_type_u;
		unsigned int oldpos = (unsigned int)file.tellg();

		file.seekg(oldpos + 0x16, ios_base::beg);
		file >> data_type;

		file.seekg(oldpos + 0x3F, ios_base::beg);
		file >> data_type_u;

		char valuesize;
		file.seekg(oldpos + 0x3D, ios_base::beg);
		file >> valuesize;

		LOG_PRINT(logfile, "	[valuesize = %d @ 0x%X]\n", (int)valuesize, ((unsigned int) file.tellg()-1));
		if(valuesize <= 0)
		{
			LOG_PRINT(logfile, "	WARNING : found strange valuesize of %d\n", (int)valuesize);
			valuesize = 10;
		}

		file.seekg(oldpos + 0x58, ios_base::beg);
		LOG_PRINT(logfile, "	[Spreadsheet @ 0x%X]\n", (unsigned int) file.tellg());

		string name(25, 0);
		file >> name;

		string::size_type pos = name.find_last_of("_");
		string columnname;
		if(pos != string::npos){
			columnname = name.substr(pos + 1);
			name.resize(pos);
		}

		LOG_PRINT(logfile, "	NAME: %s\n", name.c_str());

		unsigned int spread = 0;
		pos = name.find("DPk");//multipeak fits generate these tables
		if(columnname.empty() && pos == string::npos){
			LOG_PRINT(logfile, "NO COLUMN NAME FOUND! Must be a Matrix or Function.");
			////////////////////////////// READ matrices or functions ////////////////////////////////////
			LOG_PRINT(logfile, "	[position @ 0x%X]\n", (unsigned int) file.tellg());

			file.seekg(oldpos + 0x18, ios_base::beg);
			short signature;
			file >> signature;
			LOG_PRINT(logfile, "	SIGNATURE : %02X @ 0x%X\n", signature, (unsigned int) file.tellg());

			file.seekg(oldpos + size + 1, ios_base::beg);
			file >> size;

			file.seekg(1, ios_base::cur);
			size /= valuesize;
			LOG_PRINT(logfile, "	SIZE = %d\n", size);

			if (size == 1){
				functions.push_back(Function(name, dataIndex));
				++dataIndex;
				readFunction(colpos, valuesize, &oldpos);
			} else if (size > 1){
				if (signature == 1){
					matrices.push_back(Matrix(name));
					matrices.back().sheets.push_back(MatrixSheet(name, dataIndex));
					++dataIndex;
					readMatrixValues(data_type, data_type_u, valuesize, size);
				} else {
					LOG_PRINT(logfile, "UNKNOWN SIGNATURE, SKIP DATA\n");
					file.seekg(valuesize*size, ios_base::cur);
					++dataIndex;

					if(valuesize != 8 && valuesize <= 16)
						file.seekg(2, ios_base::cur);
				}
			}
		}
		else
		{	// worksheet
			if(speadSheets.size() == 0 || findSpreadByName(name) == -1)
Esempio n. 5
0
File: RNAz.c Progetto: wash/rnaz
int main(int argc, char *argv[])
{

  char *modelDir=NULL;              /* Directory with model files */
  struct svm_model* decision_model; /* SVM classification model */

  /* Command line options */
  int reverse=0;     /* Scan reverse complement */
  int showVersion=0; /* Shows version and exits */
  int showHelp=0;    /* Show short help and exits */
  int from=-1;       /* Scan slice from-to  */
  int to=-1;

  FILE *clust_file=stdin; /* Input file */
  FILE *out=stdout; /* Output file */

  struct aln *AS[MAX_NUM_NAMES];     
  struct aln *window[MAX_NUM_NAMES]; 
  char *tmpAln[MAX_NUM_NAMES];

  int n_seq;  /* number of input sequences */
  int length; /* length of alignment/window */
  int z_score_type;
  int decision_model_type;

  char *structure=NULL;
  char *singleStruc,*gapStruc, *output,*woGapsSeq;
  char strand[8];
  char warningString[2000];
  char warningString_regression[2000];
  char *string=NULL;
  double singleMFE,sumMFE,singleZ,sumZ,z,sci,id,decValue,prob,comb,entropy,GC;
  double min_en, real_en;
  int i,j,k,l,ll,r,countAln,nonGaps,singleGC;
  int (*readFunction)(FILE *clust,struct aln *alignedSeqs[]);
  char** lines=NULL;
  int directions[3]={FORWARD,0,0};
  int currDirection;
  struct gengetopt_args_info args;

  double meanMFE_fwd=0;
  double consensusMFE_fwd=0;
  double sci_fwd=0;
  double z_fwd=0;
  int strandGuess;
  int avoid_shuffle=0;
  double strandProb,strandDec;
  
  if (cmdline_parser (argc, argv, &args) != 0){
    usage();
    exit(EXIT_FAILURE);
  }

  if (args.help_given){
    help();
    exit(EXIT_SUCCESS);
  }

  if (args.version_given){
    version();
    exit(EXIT_SUCCESS);
  }

  if (args.outfile_given){
    out = fopen(args.outfile_arg, "w");
    if (out == NULL){
      fprintf(stderr, "ERROR: Can't open output file %s\n", args.outfile_arg);
      exit(1);
    }
  }
    

  /* Strand prediction implies both strands scored */
  if (args.predict_strand_flag){
    args.both_strands_flag=1;
  }
  
  
  if (args.forward_flag && !args.reverse_flag){
    directions[0]=FORWARD;
    directions[1]=directions[2]=0;
  }
  if (!args.forward_flag && args.reverse_flag){
    directions[0]=REVERSE;
    directions[1]=directions[2]=0;
  }
  if ((args.forward_flag && args.reverse_flag) || args.both_strands_flag){
    directions[0]=FORWARD;
    directions[1]=REVERSE;
  }

  if (args.window_given){
    if (sscanf(args.window_arg,"%d-%d",&from,&to)!=2){
      nrerror("ERROR: Invalid --window/-w command. "
              "Use it like '--window 100-200'\n");
    }
    printf("from:%d,to:%d\n",from,to);
  }

  
  if (args.inputs_num>=1){
    clust_file = fopen(args.inputs[0], "r"); 
    if (clust_file == NULL){
      fprintf(stderr, "ERROR: Can't open input file %s\n", args.inputs[0]);
      exit(1);
    }
  }

 
  /* Global RNA package variables */
  do_backtrack = 1; 
  dangles=2;

  switch(checkFormat(clust_file)){
  case CLUSTAL:
    readFunction=&read_clustal;
    break;
  case MAF:
    readFunction=&read_maf;
    break;
  case 0:
    nrerror("ERROR: Unknown alignment file format. Use Clustal W or MAF format.\n");
  }

  /* Set z-score type (mono/dinucleotide) here */
  z_score_type = 2;

  if (args.mononucleotide_given) z_score_type = 0;


  /* now let's decide which decision model to take */
  /* decision_model_type = 1 for normal model used in RNAz 1.0 */
  /* decision_model_type = 2 for normal model using dinucelotide background */
  /* decision_model_type = 3 for structural model using dinucelotide background */
  decision_model_type = 2;
  if (args.mononucleotide_given) decision_model_type = 1;
  if (args.locarnate_given) decision_model_type = 3;
  if ((args.mononucleotide_given) && args.locarnate_given){
    z_score_type=2;
    nrerror("ERROR: Structural decision model only trained with dinucleotide background model.\n");
  }

  if (args.no_shuffle_given) avoid_shuffle = 1;

  decision_model=get_decision_model(NULL, decision_model_type);

  /* Initialize Regression Models for mononucleotide */
  /* Not needed if we score with dinucleotides */
  if (z_score_type == 0) regression_svm_init();
  
  countAln=0;

  while ((n_seq=readFunction(clust_file, AS))!=0){

	if (n_seq ==1){
	  nrerror("ERROR: You need at least two sequences in the alignment.\n");
	}
	
	countAln++;
	
	length = (int) strlen(AS[0]->seq);
	
	/* if a slice is specified by the user */
  
	if ((from!=-1 || to!=-1) && (countAln==1)){
      
	  if ((from>=to)||(from<=0)||(to>length)){
		nrerror("ERROR: Invalid window range given.\n");
	  }
	  
	  sliceAln((const struct aln**)AS, (struct aln **)window, from, to);
	  length=to-from+1;
	} else { /* take complete alignment */
	  /* window=AS does not work..., deep copy seems not necessary here*/
	  from=1;
	  to=length;
	  sliceAln((const struct aln **)AS, (struct aln **)window, 1, length);
	}

	 /* Convert all Us to Ts for RNAalifold. There is a slight
	    difference in the results. During training we used alignments
	    with Ts, so we use Ts here as well. */

	for (i=0;i<n_seq;i++){
	  j=0;
	  while (window[i]->seq[j]){
		window[i]->seq[j]=toupper(window[i]->seq[j]);
		if (window[i]->seq[j]=='U') window[i]->seq[j]='T';
		++j;
	  }
	}
	
	k=0;
	while ((currDirection=directions[k++])!=0){
	  
	  if (currDirection==REVERSE){
		revAln((struct aln **)window);
		strcpy(strand,"reverse");
	  } else {
		strcpy(strand,"forward");
	  }

	  structure = (char *) space((unsigned) length+1);

	  for (i=0;window[i]!=NULL;i++){
		tmpAln[i]=window[i]->seq;
	  }
	  tmpAln[i]=NULL;

	  min_en = alifold(tmpAln, structure);
	  free_alifold_arrays();

	  comb=combPerPair(window,structure);
	  
	  sumZ=0.0;
	  sumMFE=0.0;
	  GC=0.0;

	  output=(char *)space(sizeof(char)*(length+160)*(n_seq+1)*3);

	  strcpy(warningString,"");
	  strcpy(warningString_regression,"");

	  for (i=0;i<n_seq;i++){
		singleStruc = space(strlen(window[i]->seq)+1);
		woGapsSeq = space(strlen(window[i]->seq)+1);
		j=0;
		nonGaps=0;
		singleGC=0;
		while (window[i]->seq[j]){
		  /* Convert all Ts to Us for RNAfold. There is a difference
		     between the results. With U in the function call, we get
		     the results as RNAfold gives on the command line. Since
		     this variant was also used during training, we use it here
		     as well. */
		  if (window[i]->seq[j]=='T') window[i]->seq[j]='U';
		  if (window[i]->seq[j]=='C') singleGC++;
		  if (window[i]->seq[j]=='G') singleGC++;
		  if (window[i]->seq[j]!='-'){
		    nonGaps++;
		    woGapsSeq[strlen(woGapsSeq)]=window[i]->seq[j];
		    woGapsSeq[strlen(woGapsSeq)]='\0';
		  }
		  ++j;
		}
		
		/* z-score is calculated here! */
		singleMFE = fold(woGapsSeq, singleStruc);
		free_arrays();
		/* z-score type may be overwritten. If it is out of training
		   bounds, we switch to shuffling if allowed (avoid_shuffle). */
		int z_score_type_orig = z_score_type;


		singleZ=mfe_zscore(woGapsSeq,singleMFE, &z_score_type, avoid_shuffle, warningString_regression);

		GC+=(double) singleGC/nonGaps;
		sumZ+=singleZ;
		sumMFE+=singleMFE;

		if (window[1]->strand!='?' && !args.window_given){
		  sprintf(output+strlen(output),
			  ">%s %d %d %c %d\n",
			  window[i]->name,window[i]->start,
			  window[i]->length,window[i]->strand,
			  window[i]->fullLength);
		} else {
		  sprintf(output+strlen(output),">%s\n",window[i]->name);
		}


    gapStruc= (char *) space(sizeof(char)*(strlen(window[i]->seq)+1));

    l=ll=0;

    while (window[i]->seq[l]!='\0'){
			if (window[i]->seq[l]!='-'){
			  gapStruc[l]=singleStruc[ll];
			  l++;
			  ll++;
			} else {
			  gapStruc[l]='-';
			  l++;
			}
    }
    char ch;
    ch = 'R';
    if (z_score_type == 1 || z_score_type == 3) ch = 'S';
		  		  
    sprintf(output+strlen(output),"%s\n%s ( %6.2f, z-score = %6.2f, %c)\n",
            window[i]->seq,gapStruc,singleMFE,singleZ,ch);
    z_score_type = z_score_type_orig;
		  

		free(woGapsSeq);
		free(singleStruc);
		
	  }

	  {
		int i; double s=0;
		extern int eos_debug;
		eos_debug=-1; /* shut off warnings about nonstandard pairs */
		for (i=0; window[i]!=NULL; i++) 
		  s += energy_of_struct(window[i]->seq, structure);
		real_en = s/i;
	  }

	  string = consensus((const struct aln**) window);
	  sprintf(output+strlen(output),
			  ">consensus\n%s\n%s (%6.2f = %6.2f + %6.2f) \n",
			  string, structure, min_en, real_en, min_en-real_en );
	  free(string);

	  id=meanPairID((const struct aln**)window);
	  entropy=NormShannonEntropy((const struct aln**)window);
	  z=sumZ/n_seq;
	  GC=(double)GC/n_seq;

	  if (sumMFE==0){ 
		/*Set SCI to 0 in the weird case of no structure in single
		  sequences*/
		sci=0;
	  } else {
		sci=min_en/(sumMFE/n_seq);
	  }

	  
	  	  
	  decValue=999;
	  prob=0;
	
	  classify(&prob,&decValue,decision_model,id,n_seq,z,sci,entropy,decision_model_type);

	  if (args.cutoff_given){
		if (prob<args.cutoff_arg){
		  continue;
		}
	  }

	  warning(warningString,id,n_seq,z,sci,entropy,(struct aln **)window,decision_model_type);
	  

 	  fprintf(out,"\n############################  RNAz "PACKAGE_VERSION"  ##############################\n\n"); 
 	  fprintf(out," Sequences: %u\n", n_seq); 

 	  if (args.window_given){ 
 		fprintf(out," Slice: %u to %u\n",from,to); 
 	  } 
 	  fprintf(out," Columns: %u\n",length);
 	  fprintf(out," Reading direction: %s\n",strand); 
	  fprintf(out," Mean pairwise identity: %6.2f\n", id);
	  fprintf(out," Shannon entropy: %2.5f\n", entropy);
	  fprintf(out," G+C content: %2.5f\n", GC);
 	  fprintf(out," Mean single sequence MFE: %6.2f\n", sumMFE/n_seq); 
 	  fprintf(out," Consensus MFE: %6.2f\n",min_en); 
 	  fprintf(out," Energy contribution: %6.2f\n",real_en); 
 	  fprintf(out," Covariance contribution: %6.2f\n",min_en-real_en); 
 	  fprintf(out," Combinations/Pair: %6.2f\n",comb); 
	  fprintf(out," Mean z-score: %6.2f\n",z);
	  fprintf(out," Structure conservation index: %6.2f\n",sci);
	  if (decision_model_type == 1) {
	    fprintf(out," Background model: mononucleotide\n");
	    fprintf(out," Decision model: sequence based alignment quality\n");
	  }
	  if (decision_model_type == 2) {
	    fprintf(out," Background model: dinucleotide\n");
	    fprintf(out," Decision model: sequence based alignment quality\n");
	  }
	  if (decision_model_type == 3) {
	    fprintf(out," Background model: dinucleotide\n");
	    fprintf(out," Decision model: structural RNA alignment quality\n");
	  }
 	  fprintf(out," SVM decision value: %6.2f\n",decValue); 
 	  fprintf(out," SVM RNA-class probability: %6f\n",prob); 
 	  if (prob>0.5){ 
 		fprintf(out," Prediction: RNA\n"); 
 	  } 
 	  else { 
 		fprintf(out," Prediction: OTHER\n"); 
 	  } 

	  fprintf(out,"%s",warningString_regression);

	  fprintf(out,"%s",warningString);
	  
 	  fprintf(out,"\n######################################################################\n\n"); 
	
 	  fprintf(out,"%s",output); 
	
	  fflush(out);

	  free(structure);
	  free(output);

	  if (currDirection==FORWARD && args.predict_strand_flag){
		meanMFE_fwd=sumMFE/n_seq;
		consensusMFE_fwd=min_en;
		sci_fwd=sci;
		z_fwd=z;
	  }

	  if (currDirection==REVERSE && args.predict_strand_flag){

		if (predict_strand(sci_fwd-sci, meanMFE_fwd-(sumMFE/n_seq),
						   consensusMFE_fwd-min_en, z_fwd-z, n_seq, id, 
						   &strandGuess, &strandProb, &strandDec, NULL)){
		  if (strandGuess==1){
			fprintf(out, "\n# Strand winner: forward (%.2f)\n",strandProb);
		  } else {
			fprintf(out, "\n# Strand winner: reverse (%.2f)\n",1-strandProb);
		  }
		} else {
		  fprintf(out, "\n# WARNING: No strand prediction (values out of range)\n");
		}
	  }
	}
	freeAln((struct aln **)AS);
	freeAln((struct aln **)window);
	
  }
  if (args.inputs_num>=1){
    fclose(clust_file);
  }
  cmdline_parser_free (&args);

  if (countAln==0){
	nrerror("ERROR: Empty alignment file\n");
  }
  
  
  svm_destroy_model(decision_model);
  regression_svm_free();
  
  
  return 0;
}
Esempio n. 6
0
int main() {
  int n, m, a[128][128], aa[128][128], b[128], bb[128], c[128], cc[128];
  int tmp;
  char minmax[16], buf[32], ch;

  freopen("dual.in", "r", stdin);
  freopen("dual.out", "w", stdout);
  scanf("%d%d", &n, &m);
  scanf("%s", minmax);
  readFunction(a[0], n);
  scanf(" with");
  for (int i = 1; i <= n; ++i) {
    scanf(" x%d%[^\n]", &tmp, buf);
    switch (buf[0]) {
    case ' ': c[i] = 0; break;
    case '>': c[i] = 1; break;
    case '<': c[i] = 2; break;
    }
  }
  scanf(" under");
  for (int i = 1; i <= m; ++i) {
    readFunction(a[i], n);
    ch = getchar();
    switch (ch) {
    case '=': b[i] = 0; break;
    case '>': b[i] = 1; getchar(); break;
    case '<': b[i] = 2; getchar(); break;
    }
    scanf("%d", &a[i][0]);
  }

  for (int i = 0; i <= m; ++i) {
    for (int j = 0; j <= n; ++j) {
      aa[j][i] = a[i][j];
    }
  }
  // WA
  /*		for (int i = 1; i <= m; ++i) {
        cc[i] = b[i];
        }
        for (int i = 1; i <= n; ++i) {
        bb[i] = (c[i] == 0 ? 0 : 3 - c[i]);
        }
        */		if (strcmp(minmax, "min") == 0) {
          for (int i = 1; i <= m; ++i) {
            cc[i] = b[i];
          }
          for (int i = 1; i <= n; ++i) {
            bb[i] = (c[i] == 0 ? 0 : 3 - c[i]);
          }
        } else {
          for (int i = 1; i <= m; ++i) {
            cc[i] = (b[i] == 0 ? 0 : 3 - b[i]);
          }
          for (int i = 1; i <= n; ++i) {
            bb[i] = c[i];
          }
        }


        printf("%d %d\n", m, n);
        if (strcmp(minmax, "min") == 0) {
          printf("max ");
        } else {
          printf("min ");
        }
        writeFunction(aa[0], m);
        printf("\nwith\n");
        for (int i = 1; i <= m; ++i) {
          printf("y%d%s\n", i, condition[cc[i]]);
        }
        printf("under\n");
        for (int i = 1; i <= n; ++i) {
          writeFunction(aa[i], m);
          printf("%s%d\n", restriction[bb[i]], aa[i][0]);
        }

        return 0;
}
Esempio n. 7
0
void readPackage(FILE *in) {
    static uint16_t classNextIndex = 0;

    FunctionFunctionPointer *linkingTable;
    PrepareClassFunction prepareClass;

    uint_fast8_t packageNameLength = fgetc(in);
    if (packageNameLength == 0) {
        DEBUG_LOG("Package does not have native binary");
        linkingTable = sLinkingTable;
        prepareClass = sPrepareClass;
    }
    else {
        DEBUG_LOG("Package has native binary");
        auto name = new char[packageNameLength];
        fread(name, sizeof(char), packageNameLength, in);

        uint16_t major = readUInt16(in);
        uint16_t minor = readUInt16(in);

        DEBUG_LOG("Package is named %s and has version %d.%d.x", name, major, minor);

        PackageLoadingState s = packageLoad(name, major, minor, &linkingTable, &prepareClass);

        if (s == PACKAGE_INAPPROPRIATE_MAJOR) {
            error("Installed version of package \"%s\" is incompatible with required version %d.%d. (How did you made Emojicode load this version of the package?!)", name, major, minor);
        }
        else if (s == PACKAGE_INAPPROPRIATE_MINOR) {
            error("Installed version of package \"%s\" is incompatible with required version %d.%d. Please update to the latest minor version.", name, major, minor);
        }
        else if (s == PACKAGE_LOADING_FAILED) {
            error("Could not load package \"%s\" %s.", name, packageError());
        }

        delete [] name;
    }

    for (int classCount = readUInt16(in); classCount > 0; classCount--) {
        DEBUG_LOG("➡️ Still %d class(es) to load", classCount);
        EmojicodeChar name = readEmojicodeChar(in);

        auto *klass = new Class;
        classTable[classNextIndex++] = klass;

        DEBUG_LOG("Loading class %X into %p", name, klass);

        klass->superclass = classTable[readUInt16(in)];
        int instanceVariableCount = readUInt16(in);

        int methodCount = readUInt16(in);
        klass->methodsVtable = new Function*[methodCount];

        bool inheritsInitializers = fgetc(in);
        int initializerCount = readUInt16(in);
        klass->initializersVtable = new Function*[initializerCount];

        DEBUG_LOG("Inherting intializers: %s", inheritsInitializers ? "true" : "false");

        DEBUG_LOG("%d instance variable(s); %d methods; %d initializer(s)",
                  instanceVariableCount, initializerCount, methodCount);

        uint_fast16_t localMethodCount = readUInt16(in);
        uint_fast16_t localInitializerCount = readUInt16(in);

        DEBUG_LOG("Reading %d method(s) and %d initializer(s) that are not inherited or overriden",
                  localMethodCount, localInitializerCount);

        if (klass != klass->superclass) {
            memcpy(klass->methodsVtable, klass->superclass->methodsVtable, methodCount * sizeof(Function*));
            if (inheritsInitializers) {
                memcpy(klass->initializersVtable, klass->superclass->initializersVtable,
                       initializerCount * sizeof(Function*));
            }
        }
        else {
            klass->superclass = nullptr;
        }

        for (uint_fast16_t i = 0; i < localMethodCount; i++) {
            DEBUG_LOG("Reading method %d", i);
            readFunction(klass->methodsVtable, in, linkingTable);
        }

        for (uint_fast16_t i = 0; i < localInitializerCount; i++) {
            DEBUG_LOG("Reading initializer %d", i);
            readFunction(klass->initializersVtable, in, linkingTable);
        }

        readProtocolTable(klass->protocolTable, klass->methodsVtable, in);

        // Allow inheritance from class with value, e.g. list
        klass->valueSize = klass->superclass && klass->superclass->valueSize ? klass->superclass->valueSize : 0;
        prepareClass(klass, name);
        klass->size = alignSize(sizeof(Object) + klass->valueSize + instanceVariableCount * sizeof(Value));

        klass->instanceVariableRecordsCount = readUInt16(in);
        klass->instanceVariableRecords = new FunctionObjectVariableRecord[klass->instanceVariableRecordsCount];
        for (size_t i = 0; i < klass->instanceVariableRecordsCount; i++) {
            klass->instanceVariableRecords[i].variableIndex = readUInt16(in);
            klass->instanceVariableRecords[i].condition = readUInt16(in);
            klass->instanceVariableRecords[i].type = static_cast<ObjectVariableType>(readUInt16(in));
        }

        DEBUG_LOG("Read %d object variable records", klass->instanceVariableRecordsCount);
    }

    for (int functionCount = readUInt16(in); functionCount > 0; functionCount--) {
        DEBUG_LOG("➡️ Still %d functions to come", functionCount);
        readFunction(functionTable, in, linkingTable);
    }
}