char* oph_mask_array(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
	int i;

	if (*error)
	{
	        *length=0;
	        *is_null=0;
	        *error=1;
	        return NULL;
	}
	if (*is_null || !args->lengths[2] || !args->lengths[3])
	{
	        *length=0;
	        *is_null=1;
	        *error=0;
	        return NULL;
	}

	oph_generic_param_multi* param;
	if (!initid->ptr)
	{
		param = (oph_generic_param_multi*)malloc(sizeof(oph_generic_param_multi));
		if (!param)
		{
			pmesg(1, __FILE__, __LINE__, "Error in allocating parameters\n");
			*length=0;
			*is_null=0;
			*error=1;
			return NULL;
		}
		param->measure = NULL;
		param->result = NULL;
		param->error = 0;
		param->core_oph_oper = core_oph_mask_array_multi;

		initid->ptr = (char*)param;
	}
	else param = (oph_generic_param_multi*)initid->ptr;

	if (param->error)
	{
		*length=0;
		*is_null=0;
		*error=1;
		return NULL;
	}

	oph_multistring* measure;
	if (!param->error && !param->measure)
	{
		if(core_set_oph_multistring(&measure, args->args[0], &(args->lengths[0])))
		{
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length=0;
			*is_null=0;
			*error=1;
			return NULL;
		}
		for (i=0;i<2;++i)
		{
			measure[i].length = args->lengths[2+i];
			if(!measure[i].blocksize || (measure[i].length % measure[i].blocksize) || (measure[i].islast != i))
			{
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
				*length=0;
				*is_null=0;
				*error=1;
				return NULL;
			}
			measure[i].numelem = measure[i].length / measure[i].blocksize;
		}
		if (measure[0].num_measure != measure[1].num_measure)
		{
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Number of input data types are different\n");
			*length=0;
			*is_null=0;
			*error=1;
			return NULL;
		}
		if (measure[0].length != measure[1].length)
		{
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Lengths of input arrays are different\n");
			*length=0;
			*is_null=0;
			*error=1;
			return NULL;
		}
		for (i=0;i<measure->num_measure;++i)
		{
			if (measure[0].type[i] != measure[1].type[i])
			{
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Data types of input arrays are different\n");
				*length=0;
				*is_null=0;
				*error=1;
				return NULL;
			}
		}

		param->measure = measure;
	}
	else measure = param->measure;

	for (i=0;i<2;++i) measure[i].content = args->args[2+i];

	oph_multistring* output;
	if (!param->error && !param->result)
	{
		if(core_set_oph_multistring(&output, args->args[1], &(args->lengths[1])))
		{
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length=0;
			*is_null=0;
			*error=1;
			return NULL;
		}
		output->numelem = measure->numelem;
		output->length = output->numelem * output->blocksize;
		if(!output->length)
		{
			*length=0;
			*is_null=1;
			*error=0;
			return NULL;
		}
		output->content = (char *)malloc(output->length);
		if(!output->content)
		{
			param->error = 1;
			pmesg(1,  __FILE__, __LINE__, "Error allocating measures string\n");
			*length=0;
			*is_null=0;
			*error=1;
			return NULL;
		}

		param->result = output;
	}
	else output = param->result;

	if(!param->error && core_oph_oper_array_multi(param))
	{
		param->error = 1;
		pmesg(1,  __FILE__, __LINE__, "Unable to compute result\n");
		*length=0;
		*is_null=0;
		*error=1;
		return NULL;
        }

	*length=output->length;
        *error=0;
        *is_null=0;

        return (result = output->content);
}
char *oph_gsl_complex_get_abs(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	if (*error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	if (*is_null || !args->lengths[2]) {
		*length = 0;
		*is_null = 1;
		*error = 0;
		return NULL;
	}

	oph_generic_param_multi *param;
	if (!initid->ptr) {
		param = (oph_generic_param_multi *) malloc(sizeof(oph_generic_param_multi));
		if (!param) {
			pmesg(1, __FILE__, __LINE__, "Error in allocating parameters\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param->measure = NULL;
		param->result = NULL;
		param->error = 0;
		param->extend = NULL;

		initid->ptr = (char *) param;
	} else
		param = (oph_generic_param_multi *) initid->ptr;

	if (param->error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	oph_multistring *measure;
	if (!param->error && !param->measure) {
		if (core_set_oph_multistring(&measure, args->args[0], &(args->lengths[0]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (!measure->islast) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong number of input measure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		measure->length = args->lengths[2];
		if (measure->length % measure->blocksize) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		measure->numelem = measure->length / measure->blocksize;

		param->measure = measure;
	} else
		measure = param->measure;

	measure->content = args->args[2];

	oph_multistring *output;
	if (!param->error && !param->result) {
		if (core_set_oph_multistring(&output, args->args[1], &(args->lengths[1]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (output->num_measure != measure->num_measure) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong number of output data type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		output->numelem = measure->numelem;
		output->length = output->numelem * output->blocksize;

		output->content = (char *) malloc(output->length);
		if (!output->content) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error allocating measures string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		param->result = output;
	} else
		output = param->result;

	int i, k;
	gsl_complex z;
	double tmp = 0;
	size_t run_sum1 = 0;
	size_t run_sum2 = 0;
	for (i = 0; i < measure->num_measure; i++) {
		switch (measure->type[i]) {
			case OPH_COMPLEX_INT:
				for (k = 0; k < i; k++) {
					run_sum1 += measure->elemsize[k];
					run_sum2 += output->elemsize[k];
				}
				for (k = 0; k < measure->numelem; k++) {
					z.dat[0] = (double) *((int *) (measure->content + (k * measure->blocksize) + run_sum1));	//real part
					z.dat[1] = (double) *((int *) (measure->content + (k * measure->blocksize) + run_sum1 + sizeof(int)));	//imag part
					tmp = gsl_complex_abs(z);
					if (core_oph_type_cast(&tmp, output->content + (k * output->blocksize) + run_sum2, OPH_DOUBLE, output->type[i], NULL)) {
						param->error = 1;
						pmesg(1, __FILE__, __LINE__, "Error casting output\n");
						*length = 0;
						*is_null = 0;
						*error = 1;
						return NULL;
					}
				}
				run_sum1 = 0;
				run_sum2 = 0;
				break;
			case OPH_COMPLEX_LONG:
				for (k = 0; k < i; k++) {
					run_sum1 += measure->elemsize[k];
					run_sum2 += output->elemsize[k];
				}
				for (k = 0; k < measure->numelem; k++) {
					z.dat[0] = (double) *((long long *) (measure->content + (k * measure->blocksize) + run_sum1));	//real part
					z.dat[1] = (double) *((long long *) (measure->content + (k * measure->blocksize) + run_sum1 + sizeof(long long)));	//imag part
					tmp = gsl_complex_abs(z);
					if (core_oph_type_cast(&tmp, output->content + (k * output->blocksize) + run_sum2, OPH_DOUBLE, output->type[i], NULL)) {
						param->error = 1;
						pmesg(1, __FILE__, __LINE__, "Error casting output\n");
						*length = 0;
						*is_null = 0;
						*error = 1;
						return NULL;
					}
				}
				run_sum1 = 0;
				run_sum2 = 0;
				break;
			case OPH_COMPLEX_FLOAT:
				for (k = 0; k < i; k++) {
					run_sum1 += measure->elemsize[k];
					run_sum2 += output->elemsize[k];
				}
				for (k = 0; k < measure->numelem; k++) {
					z.dat[0] = (double) *((float *) (measure->content + (k * measure->blocksize) + run_sum1));	//real part
					z.dat[1] = (double) *((float *) (measure->content + (k * measure->blocksize) + run_sum1 + sizeof(float)));	//imag part
					tmp = gsl_complex_abs(z);
					if (core_oph_type_cast(&tmp, output->content + (k * output->blocksize) + run_sum2, OPH_DOUBLE, output->type[i], NULL)) {
						param->error = 1;
						pmesg(1, __FILE__, __LINE__, "Error casting output\n");
						*length = 0;
						*is_null = 0;
						*error = 1;
						return NULL;
					}
				}
				run_sum1 = 0;
				run_sum2 = 0;
				break;
			case OPH_COMPLEX_DOUBLE:
				for (k = 0; k < i; k++) {
					run_sum1 += measure->elemsize[k];
					run_sum2 += output->elemsize[k];
				}
				for (k = 0; k < measure->numelem; k++) {
					z.dat[0] = *((double *) (measure->content + (k * measure->blocksize) + run_sum1));	//real part
					z.dat[1] = *((double *) (measure->content + (k * measure->blocksize) + run_sum1 + sizeof(double)));	//imag part
					tmp = gsl_complex_abs(z);
					if (core_oph_type_cast(&tmp, output->content + (k * output->blocksize) + run_sum2, OPH_DOUBLE, output->type[i], NULL)) {
						param->error = 1;
						pmesg(1, __FILE__, __LINE__, "Error casting output\n");
						*length = 0;
						*is_null = 0;
						*error = 1;
						return NULL;
					}
				}
				run_sum1 = 0;
				run_sum2 = 0;
				break;
			default:
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Input Type not allowed\n");
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
		}
	}

	*length = output->length;
	*error = 0;
	*is_null = 0;

	return (result = output->content);
}
char *oph_gsl_fit_linear(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	if (*error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	if (*is_null || !args->lengths[2] || !args->lengths[3] || !args->lengths[4]) {
		*length = 0;
		*is_null = 1;
		*error = 0;
		return NULL;
	}

	oph_generic_param_multi *param;
	if (!initid->ptr) {
		param = (oph_generic_param_multi *) malloc(sizeof(oph_generic_param_multi));
		if (!param) {
			pmesg(1, __FILE__, __LINE__, "Error in allocating parameters\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param->measure = NULL;
		param->result = NULL;
		param->error = 0;
		param->extend = NULL;

		initid->ptr = (char *) param;
	} else
		param = (oph_generic_param_multi *) initid->ptr;

	if (param->error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	oph_multistring *measure;
	if (!param->error && !param->measure) {
		if (core_set_oph_multistring(&measure, args->args[0], &(args->lengths[0]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (!measure->islast) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong number of input data type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		measure->length = args->lengths[2];
		if (measure->length % measure->blocksize) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		measure->numelem = measure->length / measure->blocksize;
		if (measure->numelem * sizeof(double) != args->lengths[3]) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		param->measure = measure;
	} else
		measure = param->measure;

	measure->content = args->args[2];

	oph_multistring *output;
	if (!param->error && !param->result) {
		if (core_set_oph_multistring(&output, args->args[1], &(args->lengths[1]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (output->num_measure == measure->num_measure) {
			output->length = args->lengths[4];
			if (output->length % sizeof(double)) {
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
			}
			output->numelem = output->length / sizeof(double);
			output->length = output->numelem * output->blocksize;
		} else {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong number of output data type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (!output->length) {
			*length = 0;
			*is_null = 1;
			*error = 0;
			return NULL;
		}
		output->content = (char *) malloc(output->length);
		if (!output->content) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error allocating measures string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		param->result = output;
	} else
		output = param->result;

	oph_gsl_fit_linear_param *fit;
	if (!param->extend) {
		fit = (oph_gsl_fit_linear_param *) malloc(sizeof(oph_gsl_fit_linear_param));
		if (!fit) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		fit->n = measure->numelem;
		fit->old_x = NULL;
		fit->tmp = (double *) malloc(measure->numelem * sizeof(double));	// Intermediate position of input arrays
		if (!fit->tmp) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param->extend = (void *) fit;
	} else
		fit = (oph_gsl_fit_linear_param *) param->extend;

	fit->old_x = (double *) args->args[3];
	fit->new_x = (double *) args->args[4];

	if (!param->error && core_oph_gsl_fit_linear_multi(param->measure, param->result, fit)) {
		param->error = 1;
		pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	*length = output->length;
	*error = 0;
	*is_null = 0;

	return (result = output->content);
}
char *oph_extend(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	oph_multistring *multim;
	oph_multistring *output;

	int number = 1;
	short mode = 0;

	if (!initid->extension) {
		if (core_set_oph_multistring((oph_multistring **) (&(initid->extension)), args->args[0], &(args->lengths[0]))) {
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
	}

	if (!initid->ptr) {
		if (core_set_oph_multistring(((oph_multistring **) (&(initid->ptr))), args->args[1], &(args->lengths[1]))) {
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		//Check
		if (((oph_multistring *) (initid->ptr))->num_measure != ((oph_multistring *) (initid->extension))->num_measure) {
			pmesg(1, __FILE__, __LINE__, "Wrong input or output type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
	}
	multim = (oph_multistring *) (initid->extension);
	multim->content = args->args[2];
	multim->length = args->lengths[2];

	//Check
	if (multim->length % multim->blocksize) {
		pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	multim->numelem = multim->length / multim->blocksize;
	output = (oph_multistring *) (initid->ptr);

	if (args->arg_count > 3) {
		number = *((long long *) args->args[3]);
		if (number < 1) {
			pmesg(1, __FILE__, __LINE__, "Wrong number of replies.\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
	}

	if (args->arg_count > 4) {
		if (args->lengths[4] > 2) {
			pmesg(1, __FILE__, __LINE__, "Wrong mode provided. Only 'a' or 'i' are accepted.\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (*args->args[4] == 'a')
			mode = 0;
		else if (*args->args[4] == 'i')
			mode = 1;
		else {
			pmesg(1, __FILE__, __LINE__, "Wrong mode provided. Only 'a' or 'i' are accepted.\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
	}

	output->numelem = multim->numelem * number;

	/* Allocate the right space for the result set */
	if (!output->content) {
		output->content = (char *) calloc(output->numelem, output->blocksize);
		if (!output->content) {
			pmesg(1, __FILE__, __LINE__, "Error allocating measures string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
	}

	if (core_oph_extend_multi(multim, output, number, mode)) {
		pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		*length = 0;
		*is_null = 1;
		*error = 1;
		return NULL;
	}
	*length = output->numelem * output->blocksize;
	*error = 0;
	*is_null = 0;
	return (result = ((oph_multistring *) initid->ptr)->content);

}
char* oph_sum_scalar2(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
	oph_multistring *multim;
        oph_multistring *output;

        int id = 0;
	double scalars[2];
	scalars[0] = 0;
	scalars[1] = 0;
	if(args->arg_count > 3) scalars[0] = *((double*) args->args[3]);
	if(args->arg_count > 4) scalars[1] = *((double*) args->args[4]);

        if(!initid->extension){
                if(core_set_oph_multistring( (oph_multistring**)(&(initid->extension)), args->args[0], &(args->lengths[0]))){
                        pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                }
        }

        if(!initid->ptr){
                if(core_set_oph_multistring( ((oph_multistring**)(&(initid->ptr))), args->args[1], &(args->lengths[1]))){
                        pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                }
                //Check
                if( ((oph_multistring*)(initid->ptr))->num_measure != ((oph_multistring*)(initid->extension))->num_measure){
                	pmesg(1, __FILE__, __LINE__, "Wrong input or output type\n");
                	*length=0;
                     	*is_null=0;
                	*error=1;
                	return NULL;
                }
	}
        multim = (oph_multistring*)(initid->extension);
        multim->content = args->args[2];
        multim->length = args->lengths[2];

        //Check
        if(multim->length%multim->blocksize){
        	pmesg(1,  __FILE__, __LINE__, "Wrong input type or data corrupted\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
	}
        multim->numelem = multim->length/multim->blocksize;
        output = (oph_multistring*)(initid->ptr);
	output->numelem = multim->numelem;

	if (args->arg_count>5)
	{
		id = *((long long*)args->args[5]);
		if ((id < 0) || (id > ((oph_multistring*)(initid->ptr))->num_measure))
		{
			pmesg(1,  __FILE__, __LINE__, "Wrong measure identifier. Correct values are integers in [1, %d].\n",((oph_multistring*)(initid->ptr))->num_measure);
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
	}

	/* Allocate the right space for the result set */
        if(!output->content){
                output->content=(char *)calloc(1,(output->numelem)*(output->blocksize));
                if(!output->content){
                        pmesg(1,  __FILE__, __LINE__, "Error allocating measures string\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                }
        }

        if(core_oph_sum_scalar2_multi(multim, scalars, output, id)){
        	pmesg(1,  __FILE__, __LINE__, "Unable to compute result\n");
                *length=0;
                *is_null=1;
                *error=1;
                return NULL;
        }
	*length=(output->numelem)*(output->blocksize);
        *error=0;
        *is_null=0;
        return (result = ((oph_multistring*)initid->ptr)->content);

}
char *oph_interlace(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	int i;

	if (*error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	if (*is_null) {
		*length = 0;
		*is_null = 1;
		*error = 0;
		return NULL;
	}
	for (i = 2; i < args->arg_count; ++i) {
		if (!args->lengths[i]) {
			*length = 0;
			*is_null = 1;
			*error = 0;
			return NULL;
		}
	}

	oph_generic_param_multi *param;
	if (!initid->ptr) {
		param = (oph_generic_param_multi *) malloc(sizeof(oph_generic_param_multi));
		if (!param) {
			pmesg(1, __FILE__, __LINE__, "Error in allocating parameters\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param->measure = NULL;
		param->result = NULL;
		param->error = 0;
		param->core_oph_oper = NULL;

		initid->ptr = (char *) param;
	} else
		param = (oph_generic_param_multi *) initid->ptr;

	if (param->error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	size_t num_measure_total = 0;
	oph_multistring *measure;
	if (!param->error && !param->measure) {
		if (core_set_oph_multistring(&measure, args->args[0], &(args->lengths[0]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		for (i = 0; i < args->arg_count - 2; ++i) {
			measure[i].length = args->lengths[2 + i];
			if (measure[i].length % measure[i].blocksize) {
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
			}
			measure[i].numelem = measure[i].length / measure[i].blocksize;
			num_measure_total += measure[i].num_measure;
			if (measure->numelem != measure[i].numelem) {
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Measures have different number of elements\n");
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
			}
		}

		param->measure = measure;
	} else
		measure = param->measure;

	for (i = 0; i < args->arg_count - 2; ++i)
		measure[i].content = args->args[2 + i];

	oph_multistring *output;
	if (!param->error && !param->result) {
		if (core_set_oph_multistring(&output, args->args[1], &(args->lengths[1]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (output->num_measure != num_measure_total) {
			param->error = output->num_measure != measure->num_measure;	// Simple case when all the measures are the same data type
			if (!param->error) {
				int j;
				for (i = 0; i < args->arg_count - 2; ++i) {
					if (measure[i].num_measure != measure->num_measure) {
						param->error = 1;
						break;
					}
					for (j = 0; j < measure->num_measure; ++j)
						if (measure[i].type[j] != measure->type[j]) {
							param->error = 1;
							break;
						}
					if (param->error)
						break;
				}
				if (!param->error)
					output->blocksize *= args->arg_count - 2;	// Number of input measures
			}
			if (param->error) {
				pmesg(1, __FILE__, __LINE__, "Output data type has a different number of fields from the set of input data types\n");
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
			}
		}
		output->numelem = measure->numelem;
		output->length = output->numelem * output->blocksize;
		if (!output->length) {
			*length = 0;
			*is_null = 1;
			*error = 0;
			return NULL;
		}
		output->content = (char *) malloc(output->length);
		if (!output->content) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error allocating measures string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		param->result = output;
	} else
		output = param->result;

	if (!param->error && core_oph_interlace_multi(param)) {
		param->error = 1;
		pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	*length = output->length;
	*error = 0;
	*is_null = 0;

	return (result = output->content);
}
char *oph_operator(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	if (*error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	if (*is_null || !args->lengths[2]) {
		*length = 0;
		*is_null = 1;
		*error = 0;
		return NULL;
	}

	oph_generic_param_multi *param;
	if (!initid->ptr) {
		param = (oph_generic_param_multi *) malloc(sizeof(oph_generic_param_multi));
		if (!param) {
			pmesg(1, __FILE__, __LINE__, "Error in allocating parameters\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param->measure = NULL;
		param->result = NULL;
		param->error = 0;
		param->extend = NULL;

		initid->ptr = (char *) param;
	} else
		param = (oph_generic_param_multi *) initid->ptr;

	if (param->error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	oph_multistring *measure;
	if (!param->error && !param->measure) {
		if (core_set_oph_multistring(&measure, args->args[0], &(args->lengths[0]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (!measure->islast) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong number of input measure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		measure->length = args->lengths[2];
		if (measure->length % measure->blocksize) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong input type or data corrupted\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		measure->numelem = measure->length / measure->blocksize;

		oph_request req;

		if (args->arg_count < 4)
			core_set_oper(&req, NULL, 0);
		else
			core_set_oper(&req, args->args[3], &(args->lengths[3]));
		if (!req.oper) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Operator not recognized\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		switch (req.oper) {
			case OPH_COUNT:
				param->core_oph_oper_multi = core_oph_count_multi;
				break;
			case OPH_MAX:
				param->core_oph_oper_multi = core_oph_max_multi;
				break;
			case OPH_MIN:
				param->core_oph_oper_multi = core_oph_min_multi;
				break;
			case OPH_SUM:
				param->core_oph_oper_multi = core_oph_sum_multi;
				break;
			case OPH_AVG:
				param->core_oph_oper_multi = core_oph_avg_multi;
				break;
			case OPH_STD:
				param->core_oph_oper_multi = core_oph_std_multi;
				break;
			case OPH_CMOMENT:
				param->core_oph_oper_multi = core_oph_cmoment_multi;
				break;
			case OPH_ACMOMENT:
				param->core_oph_oper_multi = core_oph_acmoment_multi;
				break;
			case OPH_RMOMENT:
				param->core_oph_oper_multi = core_oph_rmoment_multi;
				break;
			case OPH_ARMOMENT:
				param->core_oph_oper_multi = core_oph_armoment_multi;
				break;
			default:
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Unable to recognize operator\n");
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
		}

		if (args->arg_count < 5)
			core_set_hier(&req, NULL, 0);
		else
			core_set_hier(&req, args->args[4], &(args->lengths[4]));
		if (!req.hier) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Hierarchy not recognized\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		switch (req.hier) {
			case OPH_ALL:
				param->extend = (void *) 1;
				break;
			default:
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Unable to recognize hierarchy\n");
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
		}

		if (args->arg_count > 5) {
			measure->param = *((double *) (args->args[5]));
			if (measure->param < 0) {
				param->error = 1;
				pmesg(1, __FILE__, __LINE__, "Wrong parameter value 'order' %f\n", measure->param);
				*length = 0;
				*is_null = 0;
				*error = 1;
				return NULL;
			}
		} else
			measure->param = 2.0;

		param->measure = measure;
	} else
		measure = param->measure;

	double missingvalue;
	if ((args->arg_count > 6) && args->args[6]) {
		missingvalue = *((double *) (args->args[6]));
		measure->missingvalue = &missingvalue;
	} else
		measure->missingvalue = NULL;

	measure->content = args->args[2];

	oph_multistring *output;
	if (!param->error && !param->result) {
		if (core_set_oph_multistring(&output, args->args[1], &(args->lengths[1]))) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (output->num_measure != measure->num_measure) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Wrong number of output data type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		output->numelem = param->extend ? 1 : 0;
		output->length = output->numelem * output->blocksize;
		if (!output->length) {
			*length = 0;
			*is_null = 1;
			*error = 0;
			return NULL;
		}
		output->content = (char *) malloc(output->length);
		if (!output->content) {
			param->error = 1;
			pmesg(1, __FILE__, __LINE__, "Error allocating measures string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		param->result = output;
	} else
		output = param->result;

	if (!param->error && param->core_oph_oper_multi(param->measure, param->result)) {
		param->error = 1;
		pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	*length = output->length;
	*error = 0;
	*is_null = 0;

	return (result = output->content);
}
char* oph_get_subarray(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
        oph_multistring *multim;
        oph_multistring *output;

        long long size;
        long long start;
	unsigned long res_length;


	if(!initid->extension){
		if(core_set_oph_multistring( (oph_multistring**)(&(initid->extension)), args->args[0], &(args->lengths[0]))){
                        pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                }
	}

	if(!initid->ptr){
                if(core_set_oph_multistring( ((oph_multistring**)(&(initid->ptr))), args->args[1], &(args->lengths[1]))){
                        pmesg(1, __FILE__, __LINE__, "Error setting measure structure\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                }
                //Check
                if( ((oph_multistring*)(initid->ptr))->num_measure != ((oph_multistring*)(initid->extension))->num_measure){
                	pmesg(1, __FILE__, __LINE__, "Wrong input or output type\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                }
	}

	multim = (oph_multistring*)(initid->extension);
	multim->content = args->args[2];
	multim->length = args->lengths[2];
	//Check
	if(multim->length%multim->blocksize){
                pmesg(1,  __FILE__, __LINE__, "Wrong input type or data corrupted\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }
	multim->numelem = multim->length/multim->blocksize;

	output = (oph_multistring*)(initid->ptr);

	switch(args->arg_count){
                case 3:
                        //No start provided
                       	//No size provided

			start = 0;
                        size = (long long) (multim->numelem);
			output->numelem = (unsigned long) size;
        		res_length = (output->numelem)*(output->blocksize);
                        break;
                case 4:
                        //No size provided
                        start = *((long long*) args->args[3]) - 1; // Non C-like indexing

			if (start < 0)
			{
                                pmesg(1,  __FILE__, __LINE__, "Wrong argument '%lld' to oph_get_subarray function\n", start);
                                *length=0;
                                *is_null=0;
                                *error=1;
                                return NULL;
                        }

                        if(multim->numelem <= start){
                                pmesg(1,  __FILE__, __LINE__, "Start value '%lld' over limits\n",start);
                                *length=0;
                                *is_null=0;
                                *error=1;
                                return NULL;
                        }
                        size = (long long) (multim->numelem - start);
			output->numelem = (unsigned long) size;
			res_length = (output->numelem)*(output->blocksize);
                        break;
                case 5:

                        start = *((long long*) args->args[3]) - 1; // Non C-like indexing
                        size = *((long long*) args->args[4]);

			if ((start < 0) || (size <= 0))
			{
                                pmesg(1,  __FILE__, __LINE__, "Wrong arguments '%lld' or '%lld' to oph_get_subarray function\n", start, size);
                                *length=0;
                                *is_null=0;
                                *error=1;
                                return NULL;
                        }

                        if(multim->numelem <= start){
                                pmesg(1,  __FILE__, __LINE__, "Start value '%lld' over limits\n",start);
                                *length=0;
                                *is_null=0;
                                *error=1;
                                return NULL;
                        }

                        if(start + size > multim->numelem)
                                size = (long long) multim->numelem - start;
			output->numelem = (unsigned long) size;
			res_length = (output->numelem)*(output->blocksize);
                        break;
                default:
                        pmesg(1,  __FILE__, __LINE__, "Error on counting arguments\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                        break;
        }

	output->length = res_length;
        /* Allocate the right space for the result set */
        if(!output->content){
                output->content=(char *)calloc(1,output->length);
                if(!output->content){
                        pmesg(1,  __FILE__, __LINE__, "Error allocating measures string\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                }
        }

        if(core_oph_get_subarray_multi(multim, output, start)){
                pmesg(1,  __FILE__, __LINE__, "Unable to extract subarray\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }

        *length = output->length;
	*error = 0;
	*is_null = 0;
        return (result = ((oph_multistring*)(initid->ptr))->content);
}