Example #1
0
static GSList *
parse_criteria_range (Sheet *sheet, int b_col, int b_row, int e_col, int e_row,
		      int   *field_ind, gboolean anchor_end)
{
	GSList *criterias = NULL;
	GODateConventions const *date_conv =
		workbook_date_conv (sheet->workbook);
        int i, j;

	for (i = b_row; i <= e_row; i++) {
		GnmDBCriteria *new_criteria = g_new (GnmDBCriteria, 1);
		GSList *conditions = NULL;

		for (j = b_col; j <= e_col; j++) {
			GnmCriteria *cond;
			GnmCell	*cell = sheet_cell_get (sheet, j, i);
			if (cell != NULL)
				gnm_cell_eval (cell);
			if (gnm_cell_is_empty (cell))
				continue;

			cond = parse_criteria (cell->value, date_conv,
					       anchor_end);
			cond->column = (field_ind != NULL)
				? field_ind[j - b_col]
				: j - b_col;
			conditions = g_slist_prepend (conditions, cond);
		}

		new_criteria->conditions = g_slist_reverse (conditions);
		criterias = g_slist_prepend (criterias, new_criteria);
	}

	return g_slist_reverse (criterias);
}
Example #2
0
/*
 * Finds a column index of a field.
 */
int
find_column_of_field (GnmEvalPos const *ep,
		      GnmValue const *database, GnmValue const *field)
{
        Sheet *sheet;
        GnmCell  *cell;
	gchar *field_name;
	int   begin_col, end_col, row, n, column;
	int   offset;

	// I'm not certain we should demand this, but the code clearly wants
	// it.
	if (!VALUE_IS_CELLRANGE (database))
		return -1;

	offset = database->v_range.cell.a.col;

	if (VALUE_IS_FLOAT (field))
		return value_get_as_int (field) + offset - 1;

	if (!VALUE_IS_STRING (field))
		return -1;

	sheet = eval_sheet (database->v_range.cell.a.sheet, ep->sheet);
	field_name = value_get_as_string (field);
	column = -1;

	/* find the column that is labeled after `field_name' */
	begin_col = database->v_range.cell.a.col;
	end_col = database->v_range.cell.b.col;
	row = database->v_range.cell.a.row;

	for (n = begin_col; n <= end_col; n++) {
		char const *txt;
		gboolean match;

		cell = sheet_cell_get (sheet, n, row);
		if (cell == NULL)
			continue;
		gnm_cell_eval (cell);

		txt = cell->value
			? value_peek_string (cell->value)
			: "";
		match = (g_ascii_strcasecmp (field_name, txt) == 0);
		if (match) {
			column = n;
			break;
		}
	}

	g_free (field_name);
	return column;
}
Example #3
0
static GnmValue *
cb_wrapper_foreach_cell_in_area (GnmCellIter const *iter, WrapperClosure *wrap)
{
	if (iter->cell != NULL) {
		gnm_cell_eval (iter->cell);
		wrap->v_iter.v = iter->cell->value;
	} else
		wrap->v_iter.v = NULL;
	wrap->v_iter.x		= iter->pp.eval.col - wrap->base_col;
	wrap->v_iter.y		= iter->pp.eval.row - wrap->base_row;
	wrap->v_iter.cell_iter	= iter;
	return (*wrap->func) (&wrap->v_iter, wrap->user_data);
}
Example #4
0
static gnm_float
get_value (GnmNlsolve *nl)
{
	GnmValue const *v;

	gnm_cell_eval (nl->target);
	v = nl->target->value;

	if (VALUE_IS_NUMBER (v) || VALUE_IS_EMPTY (v)) {
		gnm_float y = value_get_as_float (v);
		return nl->maximize ? 0 - y : y;
	} else
		return gnm_nan;
}
Example #5
0
/**
 * parse_database_criteria:
 * @ep: #GnmEvalPos
 * @database: #GnmValue
 * @criteria: #GnmValue
 *
 * Parses the criteria cell range.
 * Returns: (element-type GnmDBCriteria) (transfer full):
 */
GSList *
parse_database_criteria (GnmEvalPos const *ep, GnmValue const *database, GnmValue const *criteria)
{
	Sheet	*sheet;
	GnmCell	*cell;
        int   i;
	int   b_col, b_row, e_col, e_row;
	int   *field_ind;

	g_return_val_if_fail (VALUE_IS_CELLRANGE (criteria), NULL);

	sheet = eval_sheet (criteria->v_range.cell.a.sheet, ep->sheet);
	b_col = criteria->v_range.cell.a.col;
	b_row = criteria->v_range.cell.a.row;
	e_col = criteria->v_range.cell.b.col;
	e_row = criteria->v_range.cell.b.row;

	if (e_col < b_col) {
		int tmp = b_col;
		b_col = e_col;
		e_col = tmp;
	}

	/* Find the index numbers for the columns of criterias */
	field_ind = g_alloca (sizeof (int) * (e_col - b_col + 1));
	for (i = b_col; i <= e_col; i++) {
		cell = sheet_cell_get (sheet, i, b_row);
		if (cell == NULL)
			continue;
		gnm_cell_eval (cell);
		if (gnm_cell_is_empty (cell))
			continue;
		field_ind[i - b_col] =
			find_column_of_field (ep, database, cell->value);
		if (field_ind[i - b_col] == -1)
			return NULL;
	}

	return parse_criteria_range (sheet, b_col, b_row + 1,
				     e_col, e_row, field_ind,
				     FALSE);
}
Example #6
0
/**
 * find_rows_that_match:
 * @sheet: #Sheet
 * @first_col: first column.
 * @first_row: first row.
 * @last_col: last column.
 * @last_row: laset row.
 * @criterias: (element-type GnmDBCriteria): the criteria to use.
 * @unique_only:
 *
 * Finds the rows from the given database that match the criteria.
 * Returns: (element-type int) (transfer full): the list of matching rows.
 **/
GSList *
find_rows_that_match (Sheet *sheet, int first_col, int first_row,
		      int last_col, int last_row,
		      GSList *criterias, gboolean unique_only)
{
	GSList	     *rows = NULL;
	GSList const *crit_ptr, *cond_ptr;
	int        row;
	gboolean   add_flag;
	char const *t1, *t2;
	GnmCell   *test_cell;
	GnmValue const *empty = value_new_empty ();

	for (row = first_row; row <= last_row; row++) {
		add_flag = TRUE;
		for (crit_ptr = criterias; crit_ptr; crit_ptr = crit_ptr->next) {
			GnmDBCriteria const *crit = crit_ptr->data;
			add_flag = TRUE;
			for (cond_ptr = crit->conditions;
			     cond_ptr != NULL ; cond_ptr = cond_ptr->next) {
				GnmCriteria *cond = cond_ptr->data;
				test_cell = sheet_cell_get (sheet, cond->column, row);
				if (test_cell != NULL)
					gnm_cell_eval (test_cell);
				if (!cond->fun (test_cell ? test_cell->value : empty, cond)) {
					add_flag = FALSE;
					break;
				}
			}

			if (add_flag)
				break;
		}
		if (add_flag) {
			gint *p;

			if (unique_only) {
				GSList *c;
				GnmCell   *cell;
				gint    i, trow;

				for (c = rows; c != NULL; c = c->next) {
					trow = *((gint *) c->data);
					for (i = first_col; i <= last_col; i++) {
						test_cell = sheet_cell_get (sheet, i, trow);
						cell = sheet_cell_get (sheet, i, row);

						/* FIXME: this is probably not right, but crashing is more wrong.  */
						if (test_cell == NULL || cell == NULL)
							continue;

						t1 = cell->value
							? value_peek_string (cell->value)
							: "";
						t2 = test_cell->value
							? value_peek_string (test_cell->value)
							: "";
						if (strcmp (t1, t2) != 0)
							goto row_ok;
					}
					goto filter_row;
row_ok:
					;
				}
			}
			p = g_new (gint, 1);
			*p = row;
			rows = g_slist_prepend (rows, (gpointer) p);
filter_row:
			;
		}
	}

	return g_slist_reverse (rows);
}
Example #7
0
static void
copy_construct_xloper_from_gnm_value (XLOPER*out, const GnmValue*in,
				      GnmFuncEvalInfo *ei)
{
	g_return_if_fail (NULL != out);

	out->xltype = xltypeMissing;
	out->val.num = 0;

	if (NULL != in) {
		switch (in->type) {
		case VALUE_EMPTY:
			out->xltype = xltypeNil;
			break;
		case VALUE_BOOLEAN:
			out->xltype = xltypeBool;
			out->val.boolean = (WORD)in->v_bool.val;
			break;
		case VALUE_FLOAT:
			out->xltype = xltypeNum;
			out->val.num = in->v_float.val;
			break;
		case VALUE_ERROR:
			out->xltype = xltypeErr;
			out->val.err = xloper_error_code_from_gnm_value (in);
			break;
		case VALUE_STRING:
			out->xltype = xltypeStr;
			out->val.str = pascal_string_from_c_string (in->v_str.val->str);
			break;
		case VALUE_CELLRANGE: {
			GnmSheetRange sr;
			GnmRangeRef const *rr = value_get_rangeref (in);
			Sheet *end_sheet = NULL;
			GnmValue *cell_value;
			GnmCell  *cell;
			gnm_rangeref_normalize (rr, ei->pos, &sr.sheet, &end_sheet, &sr.range);
			if (sr.sheet != end_sheet) {
				/* We don't attempt to flatten a 3D range to an array. */
				g_warning (_("Cannot convert 3D cell range to XLOPER."));
			} else {
				int m = sr.range.end.col-sr.range.start.col+1;
				int n = sr.range.end.row-sr.range.start.row+1;
				int i, j;

				out->xltype = xltypeMulti;
				out->val.array.lparray = ALLOC_ARRAY (XLOPER,m*n);
				out->val.array.columns = m;
				out->val.array.rows = n;
				for (i = 0; i < m; ++i) {
					for (j = 0;j<n; ++j) {
						cell = sheet_cell_get (sr.sheet,sr.range.start.col+i,sr.range.start.row+j);
						cell_value = NULL;
						if (NULL != cell) {
							gnm_cell_eval (cell);
							cell_value=cell->value;
						}
						copy_construct_xloper_from_gnm_value (out->val.array.lparray+i+j*m,cell_value,ei);
					}
				}
			}
			break;
		}
		case VALUE_ARRAY: {
			int m = in->v_array.x;
			int n = in->v_array.y;
			int i, j;

			out->xltype = xltypeMulti;
			out->val.array.lparray = ALLOC_ARRAY (XLOPER,m*n);
			out->val.array.columns = m;
			out->val.array.rows = n;
			for (i = 0; i < m; ++i) {
				for (j = 0;j < n; ++j) {
					copy_construct_xloper_from_gnm_value (out->val.array.lparray+i+j*m,in->v_array.vals[i][j],ei);
				}
			}
			break;
		}
		default:;
			g_warning (_("Unsupported GnmValue type (%d)"),in->type);
		}
	}
}
Example #8
0
/**
 * value_area_get_x_y:
 * @v: const #GnmValue *
 * @x: column
 * @y: row
 * @ep: const #GnmEvalPos *
 *
 * An internal routine to get a cell from an array or range.
 * Ensures that elements of CELLRANGE are evaluated
 *
 * If any problems occur a NULL is returned.
 **/
GnmValue const *
value_area_get_x_y (GnmValue const *v, int x, int y, GnmEvalPos const *ep)
{
	g_return_val_if_fail (v, NULL);

	if (VALUE_IS_ARRAY (v)){
		g_return_val_if_fail (x < v->v_array.x &&
				      y < v->v_array.y,
				      NULL);
		return v->v_array.vals [x][y];
	} else if (VALUE_IS_CELLRANGE (v)) {
		GnmCellRef const * const a = &v->v_range.cell.a;
		GnmCellRef const * const b = &v->v_range.cell.b;
		int a_col = a->col;
		int a_row = a->row;
		int b_col = b->col;
		int b_row = b->row;
		GnmCell *cell;
		Sheet *sheet;

		/* Handle relative references */
		if (a->col_relative)
			a_col += ep->eval.col;
		if (a->row_relative)
			a_row += ep->eval.row;
		if (b->col_relative)
			b_col += ep->eval.col;
		if (b->row_relative)
			b_row += ep->eval.row;

		/* Handle inverted references */
		if (a_row > b_row) {
			int tmp = a_row;
			a_row = b_row;
			b_row = tmp;
		}
		if (a_col > b_col) {
			int tmp = a_col;
			a_col = b_col;
			b_col = tmp;
		}

		a_col += x;
		a_row += y;

		/*
		 * FIXME FIXME FIXME
		 * This should return NA but some of the math functions may
		 * rely on this for now.
		 */
		g_return_val_if_fail (a_row<=b_row, NULL);
		g_return_val_if_fail (a_col<=b_col, NULL);

		sheet = eval_sheet (a->sheet, ep->sheet);

		g_return_val_if_fail (IS_SHEET (sheet), NULL);

		/* Speedup */
		if (sheet->cols.max_used < a_col ||
		    sheet->rows.max_used < a_row)
			return value_new_empty ();

		cell = sheet_cell_get (sheet, a_col, a_row);
		if (cell != NULL) {
			gnm_cell_eval (cell);
			return cell->value;
		}

		return value_new_empty ();
	} else
		return v;

	return NULL;
}
Example #9
0
/**
 * gnm_validation_eval:
 * @wbc:
 * @mstyle:
 * @sheet:
 *
 * validation set in the GnmStyle if applicable.
 **/
ValidationStatus
gnm_validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
		 Sheet *sheet, GnmCellPos const *pos, gboolean *showed_dialog)
{
	GnmValidation const *v;
	GnmCell *cell;
	GnmValue *val;
	gnm_float x;
	int nok, i;
	GnmEvalPos ep;

	if (showed_dialog) *showed_dialog = FALSE;

	v = gnm_style_get_validation (mstyle);
	if (v == NULL)
		return GNM_VALIDATION_STATUS_VALID;

	if (v->type == GNM_VALIDATION_TYPE_ANY)
		return GNM_VALIDATION_STATUS_VALID;

	cell = sheet_cell_get (sheet, pos->col, pos->row);
	if (cell != NULL)
		gnm_cell_eval (cell);

	if (gnm_cell_is_empty (cell)) {
		if (v->allow_blank)
			return GNM_VALIDATION_STATUS_VALID;
		BARF (g_strdup_printf (_("Cell %s is not permitted to be blank"),
				       cell_name (cell)));
	}

	val = cell->value;
	switch (val->type) {
	case VALUE_ERROR:
		if (typeinfo[v->type].errors_not_allowed)
			BARF (g_strdup_printf (_("Cell %s is not permitted to contain error values"),
					       cell_name (cell)));
		break;

	case VALUE_BOOLEAN:
		if (typeinfo[v->type].bool_always_ok)
			return GNM_VALIDATION_STATUS_VALID;
		break;

	case VALUE_STRING:
		if (typeinfo[v->type].strings_not_allowed)
			BARF (g_strdup_printf (_("Cell %s is not permitted to contain strings"),
					       cell_name (cell)));
		break;

	default:
		break;
	}

	eval_pos_init_cell (&ep, cell);

	switch (v->type) {
	case GNM_VALIDATION_TYPE_AS_INT:
		x = value_get_as_float (val);
		if (gnm_fake_floor (x) == gnm_fake_ceil (x))
			break;
		else
			BARF (g_strdup_printf (_("'%s' is not an integer"),
					       value_peek_string (val)));

	case GNM_VALIDATION_TYPE_AS_NUMBER:
		x = value_get_as_float (val);
		break;

	case GNM_VALIDATION_TYPE_AS_DATE: /* What the hell does this do?  */
		x = value_get_as_float (val);
		if (x < 0)
			BARF (g_strdup_printf (_("'%s' is not a valid date"),
					       value_peek_string (val)));
		break;


	case GNM_VALIDATION_TYPE_AS_TIME: /* What the hell does this do?  */
		x = value_get_as_float (val);
		break;

	case GNM_VALIDATION_TYPE_IN_LIST: {
		GnmExprTop const *texpr = v->deps[0].texpr;
		if (texpr) {
			GnmValue *list = gnm_expr_top_eval
				(texpr, &ep,
				 GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY);
			GnmValue *res = value_area_foreach (list, &ep, CELL_ITER_IGNORE_BLANK,
				 (GnmValueIterFunc) cb_validate_custom, val);
			value_release (list);
			if (res == NULL) {
				GnmParsePos pp;
				char *expr_str = gnm_expr_top_as_string
					(texpr,
					 parse_pos_init_evalpos (&pp, &ep),
					 ep.sheet->convs);
				char *msg = g_strdup_printf (_("%s does not contain the new value."), expr_str);
				g_free (expr_str);
				BARF (msg);
			}
		}
		return GNM_VALIDATION_STATUS_VALID;
	}

	case GNM_VALIDATION_TYPE_TEXT_LENGTH:
		/* XL appears to use a very basic value->string mapping that
		 * ignores formatting.
		 * eg len (12/13/01) == len (37238) = 5
		 * This seems wrong for
		 */
		x = g_utf8_strlen (value_peek_string (val), -1);
		break;

	case GNM_VALIDATION_TYPE_CUSTOM: {
		gboolean valid;
		GnmExprTop const *texpr = v->deps[0].texpr;

		if (!texpr)
			return GNM_VALIDATION_STATUS_VALID;

		val = gnm_expr_top_eval (texpr, &ep, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
		valid = value_get_as_bool (val, NULL);
		value_release (val);

		if (valid)
			return GNM_VALIDATION_STATUS_VALID;
		else {
			GnmParsePos pp;
			char *expr_str = gnm_expr_top_as_string
				(texpr,
				 parse_pos_init_evalpos (&pp, &ep),
				 ep.sheet->convs);
			char *msg = g_strdup_printf (_("%s is not true."), expr_str);
			g_free (expr_str);
			BARF (msg);
		}
	}

	default:
		g_assert_not_reached ();
		return GNM_VALIDATION_STATUS_VALID;
	}

	if (v->op == GNM_VALIDATION_OP_NONE)
		return GNM_VALIDATION_STATUS_VALID;

	nok = 0;
	for (i = 0; i < opinfo[v->op].nops; i++) {
		GnmExprTop const *texpr_i = v->deps[i].texpr;
		GnmExprTop const *texpr;
		GnmValue *cres;

		if (!texpr_i) {
			nok++;
			continue;
		}

		texpr = gnm_expr_top_new
			(gnm_expr_new_binary
			 (gnm_expr_new_constant (value_new_float (x)),
			  opinfo[v->op].ops[i],
			  gnm_expr_copy (texpr_i->expr)));
		cres = gnm_expr_top_eval
			(texpr, &ep, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
		if (value_get_as_bool (cres, NULL))
			nok++;
		value_release (cres);
		gnm_expr_top_unref (texpr);
	}

	if (nok < opinfo[v->op].ntrue)
		BARF (g_strdup_printf (_("%s is out of permitted range"),
				       value_peek_string (val)));

	return GNM_VALIDATION_STATUS_VALID;
}
Example #10
0
static gboolean
glpk_affine_func (GString *dst, GnmCell *target, GnmSubSolver *ssol,
                  gnm_float const *x1, gnm_float const *x2,
                  gboolean zero_too,
                  gnm_float cst, GError **err)
{
    GnmSolver *sol = GNM_SOLVER (ssol);
    unsigned ui;
    gboolean any = FALSE;
    gnm_float y;
    gboolean ok = TRUE;
    GPtrArray *input_cells = sol->input_cells;
    gnm_float *cs;

    if (!target) {
        gnm_string_add_number (dst, cst);
        return TRUE;
    }

    gnm_solver_set_vars (sol, x1);
    gnm_cell_eval (target);
    y = cst + value_get_as_float (target->value);

    cs = gnm_solver_get_lp_coeffs (sol, target, x1, x2, err);
    if (!cs)
        goto fail;

    /* Adjust constant for choice of x1.  */
    for (ui = 0; ui < input_cells->len; ui++)
        y -= x1[ui] * cs[ui];

    for (ui = 0; ui < input_cells->len; ui++) {
        GnmCell *cell = g_ptr_array_index (input_cells, ui);
        gnm_float x = cs[ui];
        if (x == 0 && !zero_too)
            continue;

        if (any) {
            if (x < 0)
                g_string_append (dst, " - ");
            else
                g_string_append (dst, " + ");
        } else {
            if (x < 0)
                g_string_append_c (dst, '-');
        }
        x = gnm_abs (x);

        if (x != 1) {
            gnm_string_add_number (dst, x);
            g_string_append_c (dst, ' ');
        }

        g_string_append (dst, glpk_var_name (ssol, cell));

        any = TRUE;
    }

    if (!any || y) {
        if (any) {
            g_string_append_c (dst, ' ');
            if (y > 0)
                g_string_append_c (dst, '+');
        }
        gnm_string_add_number (dst, y);
    }

fail:
    g_free (cs);

    return ok;
}