static CritType criteria_inspect_values (GnmValue const *x, gnm_float *xr, gnm_float *yr, GnmCriteria *crit, gboolean coerce_to_float) { GnmValue const *y = crit->x; if (x == NULL || y == NULL) return CRIT_NULL; switch (y->v_any.type) { case VALUE_BOOLEAN: /* If we're searching for a bool -- even one that is from a string search value -- we match only bools. */ if (!VALUE_IS_BOOLEAN (x)) return CRIT_WRONGTYPE; *xr = value_get_as_float (x); *yr = value_get_as_float (y); return CRIT_FLOAT; case VALUE_EMPTY: return CRIT_WRONGTYPE; case VALUE_STRING: if (!VALUE_IS_STRING (x)) return CRIT_WRONGTYPE; return CRIT_STRING; default: g_warning ("This should not happen. Please report."); return CRIT_WRONGTYPE; case VALUE_FLOAT: { GnmValue *vx; *yr = value_get_as_float (y); if (VALUE_IS_BOOLEAN (x) || VALUE_IS_ERROR (x)) return CRIT_WRONGTYPE; else if (VALUE_IS_FLOAT (x)) { *xr = value_get_as_float (x); return CRIT_FLOAT; } if (!coerce_to_float) return CRIT_WRONGTYPE; vx = format_match (value_peek_string (x), NULL, crit->date_conv); if (VALUE_IS_EMPTY (vx) || VALUE_IS_BOOLEAN (y) != VALUE_IS_BOOLEAN (vx)) { value_release (vx); return CRIT_WRONGTYPE; } *xr = value_get_as_float (vx); value_release (vx); return CRIT_FLOAT; } } }
/* * We need a horizontal strip of 5 cells containing: * * 0. Formula cell. * 1: X value cell. * 2: Y target value. * 3: Min value. * 4: Max value. */ static void dialog_goal_seek_test (Sheet *sheet, const GnmRange *range) { GoalSeekState state; GnmCell *cell; int r, c; GoalSeekStatus status; g_return_if_fail (range->start.row == range->end.row); g_return_if_fail (range->start.col + 4 == range->end.col); memset (&state, 0, sizeof (state)); r = range->start.row; c = range->start.col; state.wb = sheet->workbook; state.sheet = sheet; state.set_cell = sheet_cell_fetch (sheet, c + 0, r); state.change_cell = sheet_cell_fetch (sheet, c + 1, r); state.old_value = value_dup (state.change_cell->value); cell = sheet_cell_fetch (sheet, c + 2, r); state.target_value = value_get_as_float (cell->value); cell = sheet_cell_fetch (sheet, c + 3, r); state.xmin = VALUE_IS_EMPTY (cell->value) ? -max_range_val : value_get_as_float (cell->value); cell = sheet_cell_fetch (sheet, c + 4, r); state.xmax = VALUE_IS_EMPTY (cell->value) ? max_range_val : value_get_as_float (cell->value); status = gnumeric_goal_seek (&state); if (status == GOAL_SEEK_OK) { /* Nothing */ } else { sheet_cell_set_value (state.change_cell, value_new_error_VALUE (NULL)); } value_release (state.old_value); }
/** * value_area_fetch_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 * * Returns the element if it exists and is non-empty otherwise returns 0 **/ GnmValue const * value_area_fetch_x_y (GnmValue const *v, int x, int y, GnmEvalPos const *ep) { GnmValue const * const res = value_area_get_x_y (v, x, y, ep); if (VALUE_IS_EMPTY (res)) return value_zero; else return res; }
/* The routines to do the sorting */ static int sort_compare_cells (GnmCell const *ca, GnmCell const *cb, GnmSortClause *clause, gboolean default_locale) { GnmValue *a, *b; GnmValueType ta, tb; GnmValDiff comp = IS_EQUAL; int ans = 0; if (!ca) a = NULL; else a = ca->value; if (!cb) b = NULL; else b = cb->value; ta = VALUE_IS_EMPTY (a) ? VALUE_EMPTY : a->type; tb = VALUE_IS_EMPTY (b) ? VALUE_EMPTY : b->type; if (ta == VALUE_EMPTY && tb != VALUE_EMPTY) { comp = clause->asc ? IS_LESS : IS_GREATER; } else if (tb == VALUE_EMPTY && ta != VALUE_EMPTY) { comp = clause->asc ? IS_GREATER : IS_LESS; } else if (ta == VALUE_ERROR && tb != VALUE_ERROR) { comp = IS_GREATER; } else if (tb == VALUE_ERROR && ta != VALUE_ERROR) { comp = IS_LESS; } else { comp = default_locale ? value_compare (a, b, clause->cs) : value_compare_no_cache (a, b, clause->cs); } if (comp == IS_LESS) { ans = clause->asc ? 1 : -1; } else if (comp == IS_GREATER) { ans = clause->asc ? -1 : 1; } return ans; }
static GnmExpr const * contents_as_expr (GnmExprTop const *texpr, GnmValue const *val) { if (texpr) return gnm_expr_copy (texpr->expr); if (VALUE_IS_EMPTY (val)) return gnm_expr_new_constant (value_new_float (0.0)); if (VALUE_IS_NUMBER (val)) return gnm_expr_new_constant (value_dup (val)); return NULL; }
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; }
static void paste_cell_with_operation (Sheet *dst_sheet, int target_col, int target_row, GnmExprRelocateInfo const *rinfo, GnmCellCopy const *src, int paste_flags) { GnmCell *dst; GnmExprOp op; if (src->texpr == NULL && !VALUE_IS_EMPTY (src->val) && !VALUE_IS_NUMBER (src->val)) return; dst = sheet_cell_fetch (dst_sheet, target_col, target_row); if (!cell_has_expr_or_number_or_blank (dst)) return; op = paste_op_to_expr_op (paste_flags); /* FIXME : This does not handle arrays, linked cells, ranges, etc. */ if ((paste_flags & PASTE_CONTENTS) && (NULL != src->texpr || gnm_cell_has_expr (dst))) { GnmExpr const *old_expr = contents_as_expr (dst->base.texpr, dst->value); GnmExpr const *copied_expr = contents_as_expr (src->texpr, src->val); GnmExprTop const *res = gnm_expr_top_new (gnm_expr_new_binary (old_expr, op, copied_expr)); GnmExprTop const *relo = gnm_expr_top_relocate (res, rinfo, FALSE); if (relo) { gnm_cell_set_expr (dst, relo); gnm_expr_top_unref (relo); } else gnm_cell_set_expr (dst, res); gnm_expr_top_unref (res); } else { GnmValue *value; GnmEvalPos pos; GnmExpr const *expr = gnm_expr_new_binary ( gnm_expr_new_constant (value_dup (dst->value)), op, gnm_expr_new_constant (value_dup (src->val))); GnmExprTop const *texpr = gnm_expr_top_new (expr); eval_pos_init_cell (&pos, dst); pos.dep = NULL; /* no dynamic deps */ value = gnm_expr_top_eval (texpr, &pos, GNM_EXPR_EVAL_SCALAR_NON_EMPTY); gnm_expr_top_unref (texpr); gnm_cell_set_value (dst, value); } }
/** * cellspan_is_empty : * * Utility to ensure that a cell is completely empty. * - no spans * - no merged regions * - no content * * No need to check for merged cells here. We have already bounded the search region * using adjacent merged cells. * * We could probably have done the same thing with the span regions too, but * the current representation is not well suited to that type of search * returns TRUE if the cell is empty. */ static inline gboolean cellspan_is_empty (int col, GnmCell const *ok_span_cell) { CellSpanInfo const *span = row_span_get (ok_span_cell->row_info, col); GnmCell const *tmp; if (span != NULL && span->cell != ok_span_cell) return FALSE; tmp = sheet_cell_get (ok_span_cell->base.sheet, col, ok_span_cell->pos.row); /* FIXME : cannot use gnm_cell_is_empty until expressions can span. * because cells with expressions start out with value Empty * existing spans continue to flow through, but never get removed * because we don't respan expression results. */ return (tmp == NULL || tmp->value == NULL || (VALUE_IS_EMPTY (tmp->value) && !gnm_cell_has_expr(tmp))); }
static GnmValue * callback_function_collect_strings (GnmEvalPos const *ep, GnmValue const *value, void *closure) { char *text; collect_strings_t *cl = closure; if (VALUE_IS_EMPTY (value)) { if (cl->flags & COLLECT_IGNORE_BLANKS) text = NULL; else text = g_strdup (""); } else text = value_get_as_string (value); if (text) g_ptr_array_add (cl->data, text); return NULL; }
GnmValue * gnm_ifs_func (GPtrArray *data, GPtrArray *crits, GnmValue const *vals, float_range_function_t fun, GnmStdError err, GnmEvalPos const *ep, CollectFlags flags) { int sx, sy, x, y; unsigned ui, N = 0, nalloc = 0; gnm_float *xs = NULL; GnmValue *res = NULL; gnm_float fres; g_return_val_if_fail (data->len == crits->len, NULL); if (flags & ~(COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS | COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_ERRORS)) { g_warning ("unsupported flags in gnm_ifs_func %x", flags); } sx = value_area_get_width (vals, ep); sy = value_area_get_height (vals, ep); for (ui = 0; ui < data->len; ui++) { GnmValue const *datai = g_ptr_array_index (data, ui); if (value_area_get_width (datai, ep) != sx || value_area_get_height (datai, ep) != sy) return value_new_error_VALUE (ep); } for (y = 0; y < sy; y++) { for (x = 0; x < sx; x++) { GnmValue const *v; gboolean match = TRUE; for (ui = 0; match && ui < crits->len; ui++) { GnmCriteria *crit = g_ptr_array_index (crits, ui); GnmValue const *datai = g_ptr_array_index (data, ui); v = value_area_get_x_y (datai, x, y, ep); match = crit->fun (v, crit); } if (!match) continue; // Match. Maybe collect the data point. v = value_area_get_x_y (vals, x, y, ep); if ((flags & COLLECT_IGNORE_STRINGS) && VALUE_IS_STRING (v)) continue; if ((flags & COLLECT_IGNORE_BOOLS) && VALUE_IS_BOOLEAN (v)) continue; if ((flags & COLLECT_IGNORE_BLANKS) && VALUE_IS_EMPTY (v)) continue; if ((flags & COLLECT_IGNORE_ERRORS) && VALUE_IS_ERROR (v)) continue; if (VALUE_IS_ERROR (v)) { res = value_dup (v); goto out; } if (N >= nalloc) { nalloc = (2 * nalloc) + 100; xs = g_renew (gnm_float, xs, nalloc); } xs[N++] = value_get_as_float (v); } } if (fun (xs, N, &fres)) { res = value_new_error_std (ep, err); } else res = value_new_float (fres); out: g_free (xs); return res; }
static gboolean criteria_test_nonempty (GnmValue const *x, GnmCriteria *crit) { return !VALUE_IS_EMPTY (x); }