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); }
/* * 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; }
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); }
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; }
/** * 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); }
/** * 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); }
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); } } }
/** * 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; }
/** * 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; }
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; }