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); }
/** * paste_cell: * @target_col: Column to put the cell into * @target_row: Row to put the cell into. * @src: A #GnmCelCopy with the content to paste * @paste_flags: Bit mask that describes the paste options. * * Pastes a cell in the spreadsheet. */ static void paste_cell (int target_col, int target_row, GnmCellCopy const *src, const struct paste_cell_data *dat) { Sheet *dst_sheet = dat->pt->sheet; int paste_flags = dat->pt->paste_flags; if (paste_flags & PASTE_OPER_MASK) paste_cell_with_operation (dst_sheet, target_col, target_row, &dat->rinfo, src, paste_flags); else { GnmCell *dst = sheet_cell_fetch (dst_sheet, target_col, target_row); if (NULL != src->texpr && (paste_flags & PASTE_CONTENTS)) { GnmExprTop const *relo = gnm_expr_top_relocate ( src->texpr, &dat->rinfo, FALSE); if (paste_flags & PASTE_TRANSPOSE) { GnmExprTop const *trelo = gnm_expr_top_transpose (relo ? relo : src->texpr); if (trelo) { if (relo) gnm_expr_top_unref (relo); relo = trelo; } } else if (!relo && gnm_expr_top_is_array_corner (src->texpr)) { /* We must not share array expressions. */ relo = gnm_expr_top_new (gnm_expr_copy (src->texpr->expr)); } gnm_cell_set_expr_and_value (dst, relo ? relo : src->texpr, value_dup (src->val), TRUE); if (NULL != relo) gnm_expr_top_unref (relo); } else { GnmValue *newval = NULL; GnmValue const *oldval = src->val; if (dat->translate_dates && oldval && VALUE_IS_FLOAT (oldval)) { GOFormat const *fmt = VALUE_FMT (oldval) ? VALUE_FMT (oldval) : gnm_style_get_format (gnm_cell_get_style (dst)); if (go_format_is_date (fmt) > 0) { gnm_float fnew = go_date_conv_translate (value_get_as_float (oldval), dat->cr->date_conv, workbook_date_conv (dst_sheet->workbook)); newval = value_new_float (fnew); value_set_fmt (newval, VALUE_FMT (oldval)); } } if (!newval) newval = value_dup (src->val); gnm_cell_set_value (dst, newval); } } }
static void xlsx_write_date (XLSXWriteState *state, GsfXMLOut *xml, char const *id, gnm_float v) { GOVal *tmp = go_val_new_float (v); char *d = format_value (state->date_fmt, tmp, NULL, -1, workbook_date_conv (state->base.wb)); gsf_xml_out_add_cstr_unchecked (xml, id, d); g_free (d); go_val_free (tmp); }
/* * write_row: * * @output: the stream * @sheet: the gnumeric sheet * @row: the row number * */ static void write_row (GsfOutput *output, Sheet *sheet, gint row, GnmRange *range) { char const *text = NULL; char *formatted_string = NULL; GnmCell *cell; GnmStyle const *style; GODateConventions const *date_conv = sheet->workbook ? workbook_date_conv (sheet->workbook) : NULL; gint col; for (col = range->start.col; col <= range->end.col; col++) { GnmRange const *merge_range; GnmCellPos pos; pos.col = col; pos.row = row; merge_range = gnm_sheet_merge_contains_pos (sheet, &pos); if (merge_range != NULL) { /* If cell is inside a merged region, we use the corner cell of the merged region: */ cell = sheet_cell_get (sheet, merge_range->start.col, merge_range->start.row); } else { cell = sheet_cell_get (sheet, col, row); } if (cell != NULL && cell->value) { text = value_peek_string (cell->value); pwcsv_print_encoded (output, text); style = sheet_style_get (sheet, col, row); GOFormat const *format = gnm_style_get_format (style); // set col_width to 16-something. This works around gnumeric quirk // where, in wider cells, it formats 9,3 as 9,300000000000001 formatted_string = format_value (format, cell->value, 16, date_conv); pwcsv_print_encoded (output, formatted_string); html_write_cell_content (output, cell, style, formatted_string); g_free (formatted_string); /* Without this, we're accumulating lots of heap memory on big spreadsheets. */ gnm_cell_unrender(cell); } else { gsf_output_puts (output, ",,,"); } } gsf_output_puts (output, "\n"); }
static void sylk_write_sheet (SylkWriter *state) { GnmRange extent; /* collect style and font info */ extent = sheet_get_extent (state->sheet, FALSE, TRUE); sheet_style_foreach (state->sheet, (GFunc)cb_sylk_collect_styles, state); sheet_cell_foreach (state->sheet, (GHFunc)cb_sylk_collect_cell_styles, state); /* * 1) formats P;P..... * 2.1) ?? fonts P;F.... * 2.2) indexed fonts P;E.... * 3) global formats F; */ /* Global Formatting */ /* F;P0;DG0G10;SM0;Z;M280;N3 10 */ /* Bounds */ gsf_output_printf (state->output, "B;Y%d;X%d;D0 0 %d %d\r\n", extent.end.row + 1, extent.end.col + 1, extent.end.row, extent.end.col); /* Global options */ gsf_output_printf (state->output, "O;%c%d %f", (state->wb->iteration.enabled ? 'A' : 'G'), state->wb->iteration.max_number, state->wb->iteration.tolerance); if (!state->sheet->convs->r1c1_addresses) gsf_output_puts (state->output, ";L"); if (!state->wb->recalc_auto) gsf_output_puts (state->output, ";M"); gsf_output_printf (state->output, ";V%d", workbook_date_conv (state->wb)->use_1904 ? 4 : 0); if (state->sheet->hide_zero) gsf_output_puts (state->output, ";Z"); gsf_output_write (state->output, 2, "\r\n"); /* dump content */ state->cur_row = -1; sheet_foreach_cell_in_range (state->sheet, CELL_ITER_IGNORE_BLANK, extent.start.col, extent.start.row, extent.end.col, extent.end.row, (CellIterFunc) cb_sylk_write_cell, state); }
/* * * DO * NOT * COMPILE * DIRECTLY * * DO * NOT * COMPILE * DIRECTLY * * DO * NOT * COMPILE * DIRECTLY * * * included via xlsx-write.c **/ static void xlsx_write_pivot_val (XLSXWriteState *state, GsfXMLOut *xml, GOVal const *v) { switch (v->type) { case VALUE_CELLRANGE: case VALUE_ARRAY: g_warning ("REMOVE THIS CODE WHEN WE MOVE TO GOFFICE"); break; case VALUE_EMPTY: gsf_xml_out_simple_element (xml, "m", NULL); break; case VALUE_BOOLEAN: gsf_xml_out_start_element (xml, "b"); xlsx_add_bool (xml, "v", v->v_bool.val); gsf_xml_out_end_element (xml); break; case VALUE_FLOAT: { GOFormat const *fmt = go_val_get_fmt (v); if (NULL != fmt && go_format_is_date (fmt)) { char *d = format_value (state->date_fmt, v, NULL, -1, workbook_date_conv (state->base.wb)); gsf_xml_out_start_element (xml, "d"); gsf_xml_out_add_cstr_unchecked (xml, "v", d); gsf_xml_out_end_element (xml); } else { gsf_xml_out_start_element (xml, "n"); gsf_xml_out_add_float (xml, "v", v->v_float.val, -1); gsf_xml_out_end_element (xml); } break; } case VALUE_ERROR : gsf_xml_out_start_element (xml, "e"); gsf_xml_out_add_cstr (xml, "v", v->v_err.mesg->str); gsf_xml_out_end_element (xml); break; case VALUE_STRING : gsf_xml_out_start_element (xml, "s"); gsf_xml_out_add_cstr (xml, "v", v->v_str.val->str); gsf_xml_out_end_element (xml); break; } }
/** * gnm_cell_region_new : * @origin_sheet: optionally NULL. * * A convenience routine to create CellRegions and init the flags nicely. */ GnmCellRegion * gnm_cell_region_new (Sheet *origin_sheet) { GnmCellRegion *cr = g_new0 (GnmCellRegion, 1); cr->origin_sheet = origin_sheet; cr->date_conv = origin_sheet && origin_sheet->workbook ? workbook_date_conv (origin_sheet->workbook) : NULL; cr->cols = cr->rows = -1; cr->not_as_contents = FALSE; cr->cell_content = NULL; cr->col_state = NULL; cr->row_state = NULL; cr->styles = NULL; cr->merged = NULL; cr->objects = NULL; cr->ref_count = 1; return cr; }
/** * stf_export_cell: * @stfe: an export options struct * @cell: the cell to write to the file * * Return value: return TRUE on success, FALSE otherwise. **/ static gboolean stf_export_cell (GnmStfExport *stfe, GnmCell *cell) { char const *text = NULL; char *tmp = NULL; gboolean ok; g_return_val_if_fail (stfe != NULL, FALSE); if (cell) { switch (stfe->format) { case GNM_STF_FORMAT_PRESERVE: text = tmp = gnm_cell_get_rendered_text (cell); break; default: case GNM_STF_FORMAT_AUTO: if (cell->value) { GODateConventions const *date_conv = workbook_date_conv (cell->base.sheet->workbook); GOFormat const *format = gnm_cell_get_format (cell); text = tmp = try_auto_date (cell->value, format, date_conv); if (!text) text = tmp = try_auto_float (cell->value, format, date_conv); if (!text) text = value_peek_string (cell->value); } break; case GNM_STF_FORMAT_RAW: if (cell->value) text = value_peek_string (cell->value); break; } } ok = gsf_output_csv_write_field (GSF_OUTPUT_CSV (stfe), text ? text : "", -1); g_free (tmp); return ok; }
static GnmValue * cb_get_content (GnmCellIter const *iter, GsfOutput *buf) { GnmCell *cell; if (NULL != (cell = iter->cell)) { char *tmp; if (gnm_cell_has_expr (cell)) tmp = gnm_expr_top_as_string (cell->base.texpr, &iter->pp, iter->pp.sheet->convs); else if (VALUE_FMT (cell->value) != NULL) tmp = format_value (NULL, cell->value, -1, workbook_date_conv (iter->pp.wb)); else tmp = value_get_as_string (cell->value); gsf_output_write (buf, strlen (tmp), tmp); g_free (tmp); } gsf_output_write (buf, 1, "\n"); return NULL; }
/* * collect_floats: * * exprlist: List of expressions to evaluate. * cr: Current location (for resolving relative cells). * flags: COLLECT_IGNORE_STRINGS: silently ignore strings. * COLLECT_COERCE_STRINGS: coerce string into numbers * COLLECT_ZERO_STRINGS: count strings as 0. * (Alternative: return #VALUE!.) * COLLECT_IGNORE_BOOLS: silently ignore bools. * COLLECT_ZEROONE_BOOLS: count FALSE as 0, TRUE as 1. * (Alternative: return #VALUE!.) * COLLECT_IGNORE_SUBTOTAL : ignore expressions that include * the function SUBTOTAL directly and ignore any content * in filtered rows. * n: Output parameter for number of floats. * * Return value: * NULL in case of strict and a blank. * A copy of the error in the case of strict and an error. * Non-NULL in case of success. Then n will be set. * * Evaluate a list of expressions and return the result as an array of * gnm_float. */ static gnm_float * collect_floats (int argc, GnmExprConstPtr const *argv, GnmEvalPos const *ep, CollectFlags flags, int *n, GnmValue **error, GSList **info, gboolean *constp) { collect_floats_t cl; CellIterFlags iter_flags = CELL_ITER_ALL; GnmValue *key = NULL; CollectFlags keyflags = flags & ~COLLECT_ORDER_IRRELEVANT; gboolean strict; if (constp) *constp = FALSE; if (info) { *info = NULL; g_return_val_if_fail (!(flags & COLLECT_SORT), NULL); flags |= COLLECT_INFO; } else { if (flags & COLLECT_IGNORE_BLANKS) iter_flags = CELL_ITER_IGNORE_BLANK; flags &= ~COLLECT_INFO; } /* ---------------------------------------- */ /* Try cache. */ if (argc == 1 && (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL)) == 0) { key = get_single_cache_key (argv[0], ep); } if (key) { SingleFloatsCacheEntry *ce = get_or_fake_cache_entry (key, keyflags, ep); if (ce) { value_release (key); if (ce->error) { *error = value_dup (ce->error); return NULL; } *n = ce->n; if (constp) { *constp = TRUE; return ce->data; } return g_memdup (ce->data, *n * sizeof (gnm_float)); } } /* ---------------------------------------- */ if (flags & COLLECT_IGNORE_SUBTOTAL) iter_flags |= (CELL_ITER_IGNORE_SUBTOTAL | CELL_ITER_IGNORE_FILTERED); strict = (flags & (COLLECT_IGNORE_ERRORS | COLLECT_ZERO_ERRORS)) == 0; cl.alloc_count = 0; cl.data = NULL; cl.count = 0; cl.flags = flags; cl.info = NULL; cl.date_conv = workbook_date_conv (ep->sheet->workbook); *error = function_iterate_argument_values (ep, &callback_function_collect, &cl, argc, argv, strict, iter_flags); if (*error) { g_assert (VALUE_IS_ERROR (*error)); g_free (cl.data); cl.data = NULL; cl.count = 0; g_slist_free (cl.info); cl.info = NULL; } else { if (cl.data == NULL) { cl.alloc_count = 1; cl.data = g_new (gnm_float, cl.alloc_count); } if (flags & COLLECT_SORT) { qsort (cl.data, cl.count, sizeof (cl.data[0]), float_compare); } } if (info) *info = cl.info; *n = cl.count; if (key) { SingleFloatsCacheEntry *ce = g_new (SingleFloatsCacheEntry, 1); SingleFloatsCacheEntry *ce2; ce->value = key; ce->flags = keyflags; ce->n = *n; ce->error = value_dup (*error); if (cl.data == NULL) ce->data = NULL; else if (constp) { *constp = TRUE; ce->data = cl.data; } else ce->data = g_memdup (cl.data, MAX (1, *n) * sizeof (gnm_float)); prune_caches (); /* * We looked for the entry earlier and it was not there. * However, sub-calculation might have added it so be careful * to adjust sizes and replace the not-so-old entry. * See bug 627079. */ ce2 = g_hash_table_lookup (single_floats_cache, ce); if (ce2) total_cache_size -= 1 + ce2->n; g_hash_table_replace (single_floats_cache, ce, ce); total_cache_size += 1 + *n; } return cl.data; }
static GtkWidget * vcombo_create_list (SheetObject *so, GtkTreePath **clip, GtkTreePath **select, gboolean *make_buttons) { GnmValidationCombo *vcombo = GNM_VALIDATION_COMBO (so); unsigned i; UniqueCollection uc; GnmEvalPos ep; GtkTreeIter iter; GtkWidget *list; GPtrArray *sorted; GtkListStore *model; GnmValue *v; GnmValue const *cur_val; GnmValidation const *val = vcombo->validation; SheetView const *sv = vcombo->parent.sv; g_return_val_if_fail (val != NULL, NULL); g_return_val_if_fail (val->type == GNM_VALIDATION_TYPE_IN_LIST, NULL); g_return_val_if_fail (val->deps[0].texpr != NULL, NULL); g_return_val_if_fail (sv != NULL, NULL); eval_pos_init_editpos (&ep, sv); v = gnm_expr_top_eval (val->deps[0].texpr, &ep, GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY | GNM_EXPR_EVAL_ARRAY_CONTEXT); if (NULL == v) return NULL; uc.date_conv = workbook_date_conv (sv->sheet->workbook); uc.hash = g_hash_table_new_full ((GHashFunc)value_hash, (GEqualFunc)value_equal, (GDestroyNotify)value_release, (GDestroyNotify)g_free); value_area_foreach (v, &ep, CELL_ITER_IGNORE_BLANK, (GnmValueIterFunc) cb_collect_unique, &uc); value_release (v); sorted = g_ptr_array_new (); g_hash_table_foreach (uc.hash, (GHFunc)cb_hash_domain, sorted); qsort (&g_ptr_array_index (sorted, 0), sorted->len, sizeof (char *), &value_cmp); model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, gnm_value_get_type ()); cur_val = sheet_cell_get_value (ep.sheet, ep.eval.col, ep.eval.row); for (i = 0; i < sorted->len ; i++) { char *label = NULL; unsigned const max = 50; char const *str = g_hash_table_lookup (uc.hash, (v = g_ptr_array_index (sorted, i))); gsize len = g_utf8_strlen (str, -1); if (len > max + 3) { label = g_strdup (str); strcpy (g_utf8_offset_to_pointer (label, max), "..."); } gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, label ? label : str, /* Menu text */ 1, str, /* Actual string selected on. */ -1); g_free (label); if (i == 10) *clip = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); if (cur_val != NULL && v != NULL && value_equal (cur_val, v)) { gtk_tree_path_free (*select); *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); } } g_hash_table_destroy (uc.hash); g_ptr_array_free (sorted, TRUE); list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); g_object_unref (model); gtk_tree_view_append_column (GTK_TREE_VIEW (list), gtk_tree_view_column_new_with_attributes ("ID", gtk_cell_renderer_text_new (), "text", 0, NULL)); return list; }
void stf_dialog_format_page_init (GtkBuilder *gui, StfDialogData *pagedata) { /* GtkWidget * format_hbox; */ g_return_if_fail (gui != NULL); g_return_if_fail (pagedata != NULL); /* Create/get object and fill information struct */ pagedata->format.col_import_array = NULL; pagedata->format.col_autofit_array = NULL; pagedata->format.col_import_array_len = 0; pagedata->format.col_import_count = 0; pagedata->format.col_header = _("Column %d"); pagedata->format.format_data_container = go_gtk_builder_get_widget (gui, "format_data_container"); pagedata->format.format_trim = go_gtk_builder_get_widget (gui, "format_trim"); pagedata->format.column_selection_label = go_gtk_builder_get_widget (gui, "column_selection_label"); pagedata->format.locale_selector = GO_LOCALE_SEL (go_locale_sel_new ()); if (pagedata->locale && !go_locale_sel_set_locale (pagedata->format.locale_selector, pagedata->locale)) { g_free (pagedata->locale); pagedata->locale = go_locale_sel_get_locale (pagedata->format.locale_selector); } gtk_grid_attach ( GTK_GRID (go_gtk_builder_get_widget (gui, "locale-grid")), GTK_WIDGET (pagedata->format.locale_selector), 3, 0, 1, 1); gtk_widget_show_all (GTK_WIDGET (pagedata->format.locale_selector)); gtk_widget_set_sensitive (GTK_WIDGET (pagedata->format.locale_selector), !pagedata->fixed_locale); /* Set properties */ pagedata->format.renderdata = stf_preview_new (pagedata->format.format_data_container, workbook_date_conv (wb_control_get_workbook (WORKBOOK_CONTROL (pagedata->wbcg)))); pagedata->format.formats = g_ptr_array_new (); pagedata->format.index = -1; pagedata->format.manual_change = FALSE; /* Update widgets before connecting signals, see #333407. */ gtk_combo_box_set_active (GTK_COMBO_BOX (pagedata->format.format_trim), 0); format_page_update_column_selection (pagedata); /* Connect signals */ g_signal_connect (G_OBJECT (pagedata->format.locale_selector), "locale_changed", G_CALLBACK (locale_changed_cb), pagedata); g_signal_connect (G_OBJECT (pagedata->format.format_trim), "changed", G_CALLBACK (format_page_trim_menu_changed), pagedata); g_signal_connect (G_OBJECT (pagedata->format.renderdata->tree_view), "button_press_event", G_CALLBACK (cb_treeview_button_press), pagedata); g_signal_connect (G_OBJECT (pagedata->format.renderdata->tree_view), "key_press_event", G_CALLBACK (cb_treeview_key_press), pagedata); }
/** * clipboard_paste_region: * @cr: The GnmCellRegion to paste. * @pt: Where to paste the values. * @cc: The context for error handling. * * Pastes the supplied GnmCellRegion (@cr) into the supplied * GnmPasteTarget (@pt). This operation is not undoable. It does not auto grow * the destination if the target is a singleton. This is a simple interface to * paste a region. * * returns : TRUE if there was a problem. **/ gboolean clipboard_paste_region (GnmCellRegion const *cr, GnmPasteTarget const *pt, GOCmdContext *cc) { int repeat_horizontal, repeat_vertical, clearFlags; int dst_cols, dst_rows, src_cols, src_rows; int i, j; GSList *ptr; GnmRange const *r; gboolean has_contents, adjust_merges = TRUE; struct paste_cell_data dat; GnmRange const *merge_src; g_return_val_if_fail (pt != NULL, TRUE); g_return_val_if_fail (cr != NULL, TRUE); /* we do not need any of this fancy stuff when pasting a simple object */ if (cr->cell_content == NULL && cr->styles == NULL && cr->merged == NULL && cr->objects != NULL) { if (pt->paste_flags & (PASTE_COMMENTS | PASTE_OBJECTS)) for (ptr = cr->objects; ptr; ptr = ptr->next) paste_object (pt, ptr->data, pt->range.start.col, pt->range.start.row); return FALSE; } r = &pt->range; dst_cols = range_width (r); dst_rows = range_height (r); src_cols = cr->cols; src_rows = cr->rows; /* If the source is a single cell or a single merge */ /* Treat a target of a single merge specially, don't split the merge */ if ((src_cols == 1 && src_rows == 1) || (g_slist_length (cr->merged) == 1 && (NULL != (merge_src = cr->merged->data)) && range_height (merge_src) == cr->rows && range_width (merge_src) == cr->cols)) { GnmRange const *merge = gnm_sheet_merge_is_corner (pt->sheet, &r->start); if (merge != NULL && range_equal (r, merge)) { dst_cols = dst_rows = 1; adjust_merges = FALSE; src_cols = 1; src_rows = 1; } /* Apparently links do not supercede merges */ } else if (pt->paste_flags & PASTE_LINK) adjust_merges = FALSE; has_contents = pt->paste_flags & (PASTE_CONTENTS|PASTE_AS_VALUES|PASTE_LINK); if (pt->paste_flags & PASTE_TRANSPOSE) { int tmp = src_cols; src_cols = src_rows; src_rows = tmp; } if (cr->not_as_contents && (pt->paste_flags & PASTE_CONTENTS)) { go_cmd_context_error_invalid (cc, _("Unable to paste"), _("Contents can only be pasted by value or by link.")); return TRUE; } /* calculate the tiling */ repeat_horizontal = dst_cols/src_cols; if (repeat_horizontal * src_cols != dst_cols) { char *msg = g_strdup_printf ( _("destination does not have an even multiple of source columns (%d vs %d)\n\n" "Try selecting a single cell or an area of the same shape and size."), dst_cols, src_cols); go_cmd_context_error_invalid (cc, _("Unable to paste"), msg); g_free (msg); return TRUE; } repeat_vertical = dst_rows/src_rows; if (repeat_vertical * src_rows != dst_rows) { char *msg = g_strdup_printf ( _("destination does not have an even multiple of source rows (%d vs %d)\n\n" "Try selecting a single cell or an area of the same shape and size."), dst_rows, src_rows); go_cmd_context_error_invalid (cc, _("Unable to paste"), msg); g_free (msg); return TRUE; } if ((pt->range.start.col + dst_cols) > gnm_sheet_get_max_cols (pt->sheet) || (pt->range.start.row + dst_rows) > gnm_sheet_get_max_rows (pt->sheet)) { go_cmd_context_error_invalid (cc, _("Unable to paste"), _("result passes the sheet boundary")); return TRUE; } clearFlags = 0; /* clear the region where we will paste */ if (has_contents) clearFlags = CLEAR_VALUES | CLEAR_NORESPAN; if (pt->paste_flags & PASTE_COMMENTS) clearFlags |= CLEAR_COMMENTS; /* No need to clear the formats. We will paste over top of these. */ /* if (pt->paste_flags & PASTE_FORMATS) clearFlags |= CLEAR_FORMATS; */ if (pt->paste_flags & (PASTE_OPER_MASK | PASTE_SKIP_BLANKS)) clearFlags = 0; /* remove merged regions even for operations, or blanks */ if (has_contents && adjust_merges) clearFlags |= CLEAR_MERGES; if (clearFlags != 0) { int const dst_col = pt->range.start.col; int const dst_row = pt->range.start.row; sheet_clear_region (pt->sheet, dst_col, dst_row, dst_col + dst_cols - 1, dst_row + dst_rows - 1, clearFlags, cc); } dat.translate_dates = cr->date_conv && !go_date_conv_equal (cr->date_conv, workbook_date_conv (pt->sheet->workbook)); for (i = 0; i < repeat_horizontal ; i++) for (j = 0; j < repeat_vertical ; j++) { int const left = i * src_cols + pt->range.start.col; int const top = j * src_rows + pt->range.start.row; dat.top_left.col = left; dat.top_left.row = top; dat.rinfo.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE; dat.rinfo.origin_sheet = dat.rinfo.target_sheet = pt->sheet; if (pt->paste_flags & PASTE_EXPR_LOCAL_RELOCATE) { dat.rinfo.origin.start = cr->base; dat.rinfo.origin.end.col = cr->base.col + cr->cols - 1; dat.rinfo.origin.end.row = cr->base.row + cr->rows - 1; dat.rinfo.col_offset = left - cr->base.col; dat.rinfo.row_offset = top - cr->base.row; } else { dat.rinfo.origin = pt->range; dat.rinfo.col_offset = 0; dat.rinfo.row_offset = 0; } /* Move the styles on here so we get correct formats before recalc */ if (pt->paste_flags & PASTE_FORMATS) { if (pt->paste_flags & PASTE_TRANSPOSE) sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, (sheet_style_set_list_cb_t) range_transpose, &dat.top_left); else if (pt->paste_flags & PASTE_FLIP_H) { int data = 2 * left + src_cols - 1; sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, (sheet_style_set_list_cb_t) range_flip_h, &data); } else if (pt->paste_flags & PASTE_FLIP_V) { int data = 2 * top + src_rows - 1; sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, (sheet_style_set_list_cb_t) range_flip_v, &data); } else sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, NULL, NULL); } if (has_contents && !(pt->paste_flags & PASTE_DONT_MERGE)) { for (ptr = cr->merged; ptr != NULL ; ptr = ptr->next) { GnmRange tmp = *((GnmRange const *)ptr->data); if (pt->paste_flags & PASTE_TRANSPOSE) { int x; x = tmp.start.col; tmp.start.col = tmp.start.row; tmp.start.row = x; x = tmp.end.col; tmp.end.col = tmp.end.row; tmp.end.row = x; } if (!range_translate (&tmp, pt->sheet, left, top)) gnm_sheet_merge_add (pt->sheet, &tmp, TRUE, cc); } } if (has_contents && (pt->paste_flags & PASTE_LINK)) { paste_link (pt, top, left, cr); continue; } if (has_contents && NULL != cr->cell_content) { dat.pt = pt; dat.cr = cr; g_hash_table_foreach (cr->cell_content, (GHFunc)cb_paste_cell, &dat); } if (pt->paste_flags & (PASTE_COMMENTS | PASTE_OBJECTS)) for (ptr = cr->objects; ptr; ptr = ptr->next) paste_object (pt, ptr->data, left, top); } if (!(pt->paste_flags & PASTE_NO_RECALC)) { if (has_contents) { sheet_region_queue_recalc (pt->sheet, r); sheet_flag_status_update_range (pt->sheet, r); } else sheet_flag_style_update_range (pt->sheet, r); sheet_range_calc_spans (pt->sheet, r, (pt->paste_flags & PASTE_FORMATS) ? GNM_SPANCALC_RE_RENDER : GNM_SPANCALC_RENDER); if (pt->paste_flags & PASTE_UPDATE_ROW_HEIGHT) rows_height_update (pt->sheet, &pt->range, FALSE); sheet_redraw_all (pt->sheet, FALSE); } return FALSE; }
/** * wbcg_edit_finish: * @wbcg: #WBCGtk * @result: what should we do with the content * @showed_dialog: If non-NULL will indicate if a dialog was displayed. * * Return: TRUE if editing completed successfully, or we were no editing. **/ gboolean wbcg_edit_finish (WBCGtk *wbcg, WBCEditResult result, gboolean *showed_dialog) { Sheet *sheet; SheetView *sv; WorkbookControl *wbc; WorkbookView *wbv; g_return_val_if_fail (GNM_IS_WBC_GTK (wbcg), FALSE); wbc = GNM_WBC (wbcg); wbv = wb_control_view (wbc); wbcg_focus_cur_scg (wbcg); gnm_expr_entry_close_tips (wbcg_get_entry_logical (wbcg)); if (showed_dialog != NULL) *showed_dialog = FALSE; /* Remove the range selection cursor if it exists */ if (NULL != wbcg->rangesel) scg_rangesel_stop (wbcg->rangesel, result == WBC_EDIT_REJECT); if (!wbcg_is_editing (wbcg)) { /* We may have a guru up even if we are not editing. remove it. * Do NOT remove until later it if we are editing, it is possible * that we may want to continue editing. */ if (wbcg->edit_line.guru != NULL) { GtkWidget *w = wbcg->edit_line.guru; wbc_gtk_detach_guru (wbcg); gtk_widget_destroy (w); } return TRUE; } g_return_val_if_fail (IS_SHEET (wbcg->editing_sheet), TRUE); sheet = wbcg->editing_sheet; sv = sheet_get_view (sheet, wbv); /* Save the results before changing focus */ if (result != WBC_EDIT_REJECT) { ValidationStatus valid = GNM_VALIDATION_STATUS_VALID; char *free_txt = NULL; char const *txt; GnmStyle const *mstyle; char const *expr_txt = NULL; GOFormat const *fmt; GnmValue *value; GOUndo *u = NULL; GSList *selection = selection_get_ranges (sv, FALSE); GnmParsePos pp; GnmExprTop const *texpr = NULL; parse_pos_init_editpos (&pp, sv); /* Array only works on single range. */ if (result == WBC_EDIT_ACCEPT_ARRAY && (selection == NULL || selection->next != NULL)) result = WBC_EDIT_ACCEPT_RANGE; /******* Check whether we would split a range ********/ switch (result) { case (WBC_EDIT_ACCEPT_RANGE): case (WBC_EDIT_ACCEPT_ARRAY): { if (sheet_ranges_split_region (sheet, selection, GO_CMD_CONTEXT (wbc), _("Set Text"))) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } if (result == WBC_EDIT_ACCEPT_ARRAY && sheet_range_contains_merges_or_arrays (sheet, selection->data, GO_CMD_CONTEXT (wbc), _("Set Text"), TRUE, FALSE)) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } break; } case (WBC_EDIT_ACCEPT_WO_AC): case (WBC_EDIT_ACCEPT): { GnmCell const *cell = sheet_cell_get (sheet, sv->edit_pos.col, sv->edit_pos.row); if (gnm_cell_is_nonsingleton_array (cell)) { gnm_cmd_context_error_splits_array (GO_CMD_CONTEXT (wbc), _("Set Text"), NULL); if (showed_dialog != NULL) *showed_dialog = TRUE; range_fragment_free (selection); return FALSE; } break; } case (WBC_EDIT_REJECT): default: /* We should not be able to get here! */ break; } /******* Check whether the range is locked ********/ switch (result) { case (WBC_EDIT_ACCEPT_RANGE): case (WBC_EDIT_ACCEPT_ARRAY): { if (cmd_selection_is_locked_effective (sheet, selection, wbc, _("Set Text"))) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } break; } case (WBC_EDIT_ACCEPT_WO_AC): case (WBC_EDIT_ACCEPT): { GnmRange r; r.end = r.start = pp.eval; if (cmd_cell_range_is_locked_effective (sheet, &r, wbc, _("Set Text"))) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } break; } case (WBC_EDIT_REJECT): default: /* We should not be able to get here! */ break; } /*****************************************************/ txt = wbcg_edit_get_display_text (wbcg); mstyle = sheet_style_get (sheet, sv->edit_pos.col, sv->edit_pos.row); fmt = gnm_cell_get_format (sheet_cell_fetch (sheet, sv->edit_pos.col, sv->edit_pos.row)); value = format_match (txt, fmt, workbook_date_conv (sheet->workbook)); if (value == NULL) expr_txt = gnm_expr_char_start_p (txt); else value_release (value); /* NOTE : do not modify gnm_expr_char_start_p to exclude "-" * it _can_ start an expression, which is required for rangesel * it just isn't an expression. */ if (expr_txt != NULL && *expr_txt != '\0' && strcmp (expr_txt, "-")) { GnmExprTop const *texpr_test = NULL; GnmParseError perr; parse_error_init (&perr); texpr_test = gnm_expr_parse_str (expr_txt, &pp, GNM_EXPR_PARSE_DEFAULT, NULL, &perr); /* Try adding a single extra closing paren to see if it helps */ if (texpr_test == NULL && perr.err != NULL && perr.err->code == PERR_MISSING_PAREN_CLOSE) { GnmParseError tmp_err; char *tmp = g_strconcat (txt, ")", NULL); parse_error_init (&tmp_err); texpr_test = gnm_expr_parse_str (gnm_expr_char_start_p (tmp), &pp, GNM_EXPR_PARSE_DEFAULT, NULL, &tmp_err); parse_error_free (&tmp_err); if (texpr_test != NULL) { txt = free_txt = tmp; expr_txt = gnm_expr_char_start_p (txt); } else g_free (tmp); } if (texpr_test == NULL && perr.err != NULL) { ValidationStatus reedit; /* set focus _before_ selection. gtk2 seems to * screw with selection in gtk_entry_grab_focus * (no longer required now that we clear * gtk-entry-select-on-focus) */ gtk_window_set_focus (wbcg_toplevel (wbcg), (GtkWidget *) wbcg_get_entry (wbcg)); if (perr.begin_char != 0 || perr.end_char != 0) { int offset = expr_txt - txt; gtk_editable_select_region (GTK_EDITABLE (wbcg_get_entry (wbcg)), offset + perr.begin_char, offset + perr.end_char); } else gtk_editable_set_position ( GTK_EDITABLE (wbcg_get_entry (wbcg)), -1); reedit = wb_control_validation_msg (GNM_WBC (wbcg), GNM_VALIDATION_STYLE_PARSE_ERROR, NULL, perr.err->message); if (showed_dialog != NULL) *showed_dialog = TRUE; parse_error_free (&perr); if (reedit == GNM_VALIDATION_STATUS_INVALID_EDIT) { range_fragment_free (selection); return FALSE; } /* restore focus to sheet , or we'll leave edit * mode only to jump right back in the new * cell because it looks like someone just * focused on the edit line (eg hit F2) */ wbcg_focus_cur_scg (wbcg); } if (texpr_test != NULL) gnm_expr_top_unref (texpr_test); } /* We only enter an array formula if the text is a formula */ if (result == WBC_EDIT_ACCEPT_ARRAY && !expr_txt) result = WBC_EDIT_ACCEPT_RANGE; if (result == WBC_EDIT_ACCEPT_ARRAY) { GnmParsePos pp_array; GnmRange *r = selection->data; parse_pos_init (&pp_array, sheet->workbook, sheet, r->start.col, r->start.row); if ((texpr = gnm_expr_parse_str (expr_txt, &pp_array, GNM_EXPR_PARSE_DEFAULT, sheet_get_conventions (sheet), NULL)) == NULL) result = WBC_EDIT_ACCEPT_RANGE; } /* We need to save the information that we will temporarily overwrite */ /* We then assign the information. No need to worry about formatting */ /* Finally we can check the validation! */ switch (result) { case (WBC_EDIT_ACCEPT_RANGE): { GSList *l; for (l = selection; l != NULL; l = l->next) { GnmRange *r = l->data; u = go_undo_combine (u, clipboard_copy_range_undo (sheet, r)); } for (l = selection; l != NULL; l = l->next) { GnmRange *r = l->data; /* We do this separately since there may be overlap between ranges */ sheet_range_set_text (&pp, r, txt); valid = gnm_validation_eval_range (wbc, sheet, &sv->edit_pos, r, showed_dialog); if (valid != GNM_VALIDATION_STATUS_VALID) break; } break; } case (WBC_EDIT_ACCEPT_ARRAY): { GnmRange *r = selection->data; u = go_undo_combine (u, clipboard_copy_range_undo (sheet, r)); if (texpr) { gnm_expr_top_ref (texpr); gnm_cell_set_array_formula (sheet, r->start.col, r->start.row, r->end.col, r->end.row, texpr); sheet_region_queue_recalc (sheet, r); } valid = gnm_validation_eval_range (wbc, sheet, &sv->edit_pos, r, showed_dialog); break; } case (WBC_EDIT_ACCEPT_WO_AC): case (WBC_EDIT_ACCEPT): { GnmRange r; GnmCell *cell; range_init_cellpos (&r, &sv->edit_pos); u = clipboard_copy_range_undo (sheet, &r); cell = sheet_cell_fetch (sheet, sv->edit_pos.col, sv->edit_pos.row); sheet_cell_set_text (cell, txt, wbcg->edit_line.markup); valid = gnm_validation_eval (wbc, mstyle, sheet, &sv->edit_pos, showed_dialog); break; } case (WBC_EDIT_REJECT): default: /* We should not be able to get here! */ break; } range_fragment_free (selection); /* We need to rebuild the original info first. */ go_undo_undo (u); g_object_unref (u); /* Now we can respond to our validation information */ if (valid != GNM_VALIDATION_STATUS_VALID) { result = WBC_EDIT_REJECT; if (valid == GNM_VALIDATION_STATUS_INVALID_EDIT) { gtk_window_set_focus (wbcg_toplevel (wbcg), (GtkWidget *) wbcg_get_entry (wbcg)); g_free (free_txt); if (texpr != NULL) gnm_expr_top_unref (texpr); return FALSE; } } else { if (result == WBC_EDIT_ACCEPT_ARRAY) { cmd_area_set_array_expr (wbc, sv, texpr); } else { PangoAttrList *res_markup = wbcg->edit_line.markup ? pango_attr_list_copy (wbcg->edit_line.markup) : NULL; if (result == WBC_EDIT_ACCEPT) cmd_set_text (wbc, sheet, &sv->edit_pos, txt, res_markup, TRUE); else if (result == WBC_EDIT_ACCEPT_WO_AC) cmd_set_text (wbc, sheet, &sv->edit_pos, txt, res_markup, FALSE); else cmd_area_set_text (wbc, sv, txt, res_markup); if (res_markup) pango_attr_list_unref (res_markup); } } if (texpr != NULL) gnm_expr_top_unref (texpr); g_free (free_txt); } else { if (sv == wb_control_cur_sheet_view (wbc)) { /* Redraw the cell contents in case there was a span */ GnmRange tmp; tmp.start = tmp.end = sv->edit_pos; sheet_range_bounding_box (sv->sheet, &tmp); sv_redraw_range (wb_control_cur_sheet_view (wbc), &tmp); } /* Reload the entry widget with the original contents */ wb_view_edit_line_set (wbv, wbc); } /* Stop editing */ wbcg->editing = FALSE; wbcg->editing_sheet = NULL; wbcg->editing_cell = NULL; if (wbcg->edit_line.guru != NULL) { GtkWidget *w = wbcg->edit_line.guru; wbc_gtk_detach_guru (wbcg); gtk_widget_destroy (w); } if (wbcg->edit_line.signal_insert) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_insert); wbcg->edit_line.signal_insert = 0; } if (wbcg->edit_line.signal_delete) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_delete); wbcg->edit_line.signal_delete = 0; } if (wbcg->edit_line.signal_cursor_pos) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_cursor_pos); wbcg->edit_line.signal_cursor_pos = 0; } if (wbcg->edit_line.signal_selection_bound) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_selection_bound); wbcg->edit_line.signal_selection_bound = 0; } if (wbcg->edit_line.cell_attrs != NULL) { pango_attr_list_unref (wbcg->edit_line.cell_attrs); wbcg->edit_line.cell_attrs = NULL; } if (wbcg->edit_line.markup) { pango_attr_list_unref (wbcg->edit_line.markup); wbcg->edit_line.markup = NULL; } if (wbcg->edit_line.full_content != NULL) { pango_attr_list_unref (wbcg->edit_line.full_content); wbcg->edit_line.full_content = NULL; } if (wbcg->edit_line.cur_fmt) { pango_attr_list_unref (wbcg->edit_line.cur_fmt); wbcg->edit_line.cur_fmt = NULL; } /* set pos to 0, to ensure that if we start editing by clicking on the * editline at the last position, we'll get the right style feedback */ gtk_editable_set_position ((GtkEditable *) wbcg_get_entry (wbcg), 0); wb_control_update_action_sensitivity (wbc); if (!sheet->workbook->during_destruction) { /* restore focus to original sheet in case things were being selected * on a different page. Do no go through the view, rangesel is * specific to the control. */ wb_control_sheet_focus (wbc, sheet); /* Only the edit sheet has an edit cursor */ scg_edit_stop (wbcg_cur_scg (wbcg)); } wbcg_auto_complete_destroy (wbcg); wb_control_style_feedback (wbc, NULL); /* in case markup messed with things */ return TRUE; }
/** * cb_dialog_apply_clicked: * @button: * @state: * * Close (destroy) the dialog **/ static void cb_dialog_apply_clicked (G_GNUC_UNUSED GtkWidget *button, GoalSeekState *state) { char *status_str; GoalSeekStatus status; GnmValue *target; GnmRangeRef const *r; GOFormat *format; if (state->warning_dialog != NULL) gtk_widget_destroy (state->warning_dialog); /* set up source */ target = gnm_expr_entry_parse_as_value (state->set_cell_entry, state->sheet); if (target == NULL) { go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog), &(state->warning_dialog), GTK_MESSAGE_ERROR, _("You should introduce a valid cell " "name in 'Set Cell:'!")); gnm_expr_entry_grab_focus (state->set_cell_entry, TRUE); return; } r = &target->v_range.cell; state->set_cell = sheet_cell_get (r->a.sheet, r->a.col, r->a.row); value_release (target); if (state->set_cell == NULL || !gnm_cell_has_expr (state->set_cell)) { go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog), &(state->warning_dialog), GTK_MESSAGE_ERROR, _("The cell named in 'Set Cell:' " "must contain a formula!")); gnm_expr_entry_grab_focus (state->set_cell_entry, TRUE); return; } /* set up source */ target = gnm_expr_entry_parse_as_value (state->change_cell_entry, state->sheet); if (target == NULL) { go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog), &(state->warning_dialog), GTK_MESSAGE_ERROR, _("You should introduce a valid cell " "name in 'By Changing Cell:'!")); gnm_expr_entry_grab_focus (state->change_cell_entry, TRUE); return; } r = &target->v_range.cell; state->change_cell = sheet_cell_fetch (r->a.sheet, r->a.col, r->a.row); value_release (target); if (gnm_cell_has_expr (state->change_cell)) { go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog), &(state->warning_dialog), GTK_MESSAGE_ERROR, _("The cell named in 'By changing cell' " "must not contain a formula.")); gnm_expr_entry_grab_focus (state->change_cell_entry, TRUE); return; } format = gnm_style_get_format (gnm_cell_get_style (state->set_cell)); if (entry_to_float_with_format (GTK_ENTRY(state->to_value_entry), &state->target_value, TRUE, format)){ go_gtk_notice_nonmodal_dialog (GTK_WINDOW(state->dialog), &(state->warning_dialog), GTK_MESSAGE_ERROR, _("The value given in 'To Value:' " "is not valid.")); focus_on_entry (GTK_ENTRY(state->to_value_entry)); return; } format = gnm_style_get_format (gnm_cell_get_style (state->change_cell)); if (entry_to_float_with_format (GTK_ENTRY(state->at_least_entry), &state->xmin, TRUE, format)) { state->xmin = -max_range_val; gtk_entry_set_text (GTK_ENTRY (state->at_least_entry), ""); } if (entry_to_float_with_format (GTK_ENTRY(state->at_most_entry), &state->xmax, TRUE, format)) { state->xmax = +max_range_val; gtk_entry_set_text (GTK_ENTRY (state->at_most_entry), ""); } if ((state->old_cell != NULL) && (state->old_value != NULL)) { sheet_cell_set_value (state->old_cell, state->old_value); workbook_recalc (state->wb); state->old_value = NULL; } state->old_cell = state->change_cell; state->old_value = value_dup (state->change_cell->value); status = gnumeric_goal_seek (state); switch (status) { case GOAL_SEEK_OK: { const char *actual_str; const char *solution_str; GOFormat *format = go_format_general (); GnmValue *error_value = value_new_float (state->target_value - value_get_as_float (state->set_cell->value)); char *target_str = format_value (format, error_value, NULL, -1, workbook_date_conv (state->wb)); gtk_label_set_text (GTK_LABEL (state->target_value_label), target_str); g_free (target_str); value_release (error_value); status_str = g_strdup_printf (_("Goal seeking with cell %s found a solution."), cell_name (state->set_cell)); gtk_label_set_text (GTK_LABEL (state->result_label), status_str); g_free (status_str); /* FIXME? Do a format? */ actual_str = state->set_cell->value ? value_peek_string (state->set_cell->value) : ""; gtk_label_set_text (GTK_LABEL (state->current_value_label), actual_str); solution_str = state->change_cell->value ? value_peek_string (state->change_cell->value) : ""; gtk_label_set_text (GTK_LABEL (state->solution_label), solution_str); break; } default: status_str = g_strdup_printf (_("Goal seeking with cell %s did not find a solution."), cell_name (state->set_cell)); gtk_label_set_text (GTK_LABEL (state->result_label), status_str); g_free (status_str); gtk_label_set_text (GTK_LABEL (state->current_value_label), ""); gtk_label_set_text (GTK_LABEL (state->solution_label), ""); gtk_label_set_text (GTK_LABEL (state->target_value_label), ""); break; } state->cancelled = FALSE; gtk_widget_show (state->result_table); return; }
/** * FIXME: In the long term this needs optimising. **/ static GnmValue * val_to_base (GnmFuncEvalInfo *ei, GnmValue const *value, GnmValue const *aplaces, int src_base, int dest_base, gnm_float min_value, gnm_float max_value, Val2BaseFlags flags) { int digit, min, max, places; gnm_float v; GString *buffer; GnmValue *vstring = NULL; g_return_val_if_fail (src_base > 1 && src_base <= 36, value_new_error_VALUE (ei->pos)); g_return_val_if_fail (dest_base > 1 && dest_base <= 36, value_new_error_VALUE (ei->pos)); /* func.c ought to take care of this. */ if (VALUE_IS_BOOLEAN (value)) return value_new_error_VALUE (ei->pos); if (aplaces && VALUE_IS_BOOLEAN (aplaces)) return value_new_error_VALUE (ei->pos); switch (value->type) { default: return value_new_error_NUM (ei->pos); case VALUE_STRING: if (flags & V2B_STRINGS_GENERAL) { vstring = format_match_number (value_peek_string (value), NULL, workbook_date_conv (ei->pos->sheet->workbook)); if (!vstring || !VALUE_IS_FLOAT (vstring)) { value_release (vstring); return value_new_error_VALUE (ei->pos); } } else { char const *str = value_peek_string (value); size_t len; gboolean hsuffix = FALSE; char *err; if ((flags & V2B_STRINGS_BLANK_ZERO) && *str == 0) str = "0"; /* This prevents leading spaces, signs, etc, and "". */ if (!g_ascii_isalnum (*str)) return value_new_error_NUM (ei->pos); len = strlen (str); /* We check length in bytes. Since we are going to require nothing but digits, that is fine. */ if ((flags & V2B_STRINGS_MAXLEN) && len > 10) return value_new_error_NUM (ei->pos); if (flags & V2B_STRINGS_0XH) { if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) str += 2; else if (str[len - 1] == 'h' || str[len - 1] == 'H') hsuffix = TRUE; } v = g_ascii_strtoll (str, &err, src_base); if (err == str || err[hsuffix] != 0) return value_new_error_NUM (ei->pos); if (v < min_value || v > max_value) return value_new_error_NUM (ei->pos); break; } /* Fall through. */ case VALUE_FLOAT: { gnm_float val = gnm_fake_trunc (value_get_as_float (vstring ? vstring : value)); char buf[GNM_MANT_DIG + 10]; char *err; value_release (vstring); if (val < min_value || val > max_value) return value_new_error_NUM (ei->pos); g_ascii_formatd (buf, sizeof (buf) - 1, "%.0" GNM_FORMAT_f, val); v = g_ascii_strtoll (buf, &err, src_base); if (*err != 0) return value_new_error_NUM (ei->pos); break; } } if (src_base != 10) { gnm_float b10 = gnm_pow (src_base, 10); if (v >= b10 / 2) /* N's complement */ v = v - b10; } if (flags & V2B_NUMBER) return value_new_float (v); if (v < 0) { min = 1; max = 10; v += gnm_pow (dest_base, max); } else { if (v == 0) min = max = 1; else min = max = (int)(gnm_log (v + 0.5) / gnm_log (dest_base)) + 1; } if (aplaces) { gnm_float fplaces = value_get_as_float (aplaces); if (fplaces < min || fplaces > 10) return value_new_error_NUM (ei->pos); places = (int)fplaces; if (v >= 0 && places > max) max = places; } else places = 1; buffer = g_string_sized_new (max); g_string_set_size (buffer, max); for (digit = max - 1; digit >= 0; digit--) { int thisdigit = gnm_fmod (v + 0.5, dest_base); v = gnm_floor ((v + 0.5) / dest_base); buffer->str[digit] = thisdigit["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"]; } return value_new_string_nocopy (g_string_free (buffer, FALSE)); }