/** * parse_criteria: * @crit_val: #GnmValue * @date_conv: #GODateConventions * * Returns: (transfer full): GnmCriteria which caller must free. * * ">=value" * "<=value" * "<>value" * "<value" * ">value" * "=value" * "pattern" **/ GnmCriteria * parse_criteria (GnmValue const *crit_val, GODateConventions const *date_conv, gboolean anchor_end) { int len; char const *criteria; GnmCriteria *res = g_new0 (GnmCriteria, 1); GnmValue *empty; res->iter_flags = CELL_ITER_IGNORE_BLANK; res->date_conv = date_conv; if (VALUE_IS_NUMBER (crit_val)) { res->fun = criteria_test_equal; res->x = value_dup (crit_val); return res; } criteria = value_peek_string (crit_val); if (strncmp (criteria, "<=", 2) == 0) { res->fun = criteria_test_less_or_equal; len = 2; } else if (strncmp (criteria, ">=", 2) == 0) { res->fun = criteria_test_greater_or_equal; len = 2; } else if (strncmp (criteria, "<>", 2) == 0) { /* "<>" by itself is special: */ res->fun = (criteria[2] == 0) ? criteria_test_nonempty : criteria_test_unequal; len = 2; } else if (*criteria == '<') { res->fun = criteria_test_less; len = 1; } else if (*criteria == '=') { /* "=" by itself is special: */ res->fun = (criteria[1] == 0) ? criteria_test_empty : criteria_test_equal; len = 1; } else if (*criteria == '>') { res->fun = criteria_test_greater; len = 1; } else { res->fun = criteria_test_match; res->has_rx = (gnm_regcomp_XL (&res->rx, criteria, GO_REG_ICASE, TRUE, anchor_end) == GO_REG_OK); len = 0; } res->x = format_match_number (criteria + len, NULL, date_conv); if (res->x == NULL) res->x = value_new_string (criteria + len); else if (len == 0 && VALUE_IS_NUMBER (res->x)) res->fun = criteria_test_equal; empty = value_new_empty (); if (res->fun (empty, res)) res->iter_flags &= ~CELL_ITER_IGNORE_BLANK; value_release (empty); res->ref_count = 1; return res; }
gboolean go_conf_set_value_from_str (GOConfNode *node, gchar const *key, gchar const *val_str) { switch (go_conf_node_get_key_type (node, key)) { case G_TYPE_STRING: go_conf_set_string (node, key, val_str); break; case G_TYPE_FLOAT: { GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */ GnmValue *value = format_match_number (val_str, NULL, conv); if (value != NULL) { gnm_float the_float = value_get_as_float (value); go_conf_set_double (node, key, the_float); } value_release (value); break; } case G_TYPE_INT: { GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */ GnmValue *value = format_match_number (val_str, NULL, conv); if (value != NULL) { gint the_int = value_get_as_int (value); go_conf_set_int (node, key, the_int); } value_release (value); break; } case G_TYPE_BOOLEAN: { GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */ GnmValue *value = format_match_number (val_str, NULL, conv); gboolean err, the_bool; if (value != NULL) { err = FALSE; the_bool = value_get_as_bool (value, &err); go_conf_set_bool (node, key, the_bool); } value_release (value); break; } default: g_warning ("Unsupported gconf type in preference dialog"); } return TRUE; }
gnm_float datetime_value_to_serial_raw (GnmValue const *v, GODateConventions const *conv) { gnm_float serial; if (VALUE_IS_NUMBER (v)) serial = value_get_as_float (v); else { char const *str = value_peek_string (v); GnmValue *conversion = format_match_number (str, go_format_default_date (), conv); if (conversion) { serial = value_get_as_float (conversion); value_release (conversion); } else serial = G_MAXINT; } if (serial < 0 && !gnm_datetime_allow_negative ()) serial = G_MAXINT; return serial; }
static GnmValue * callback_function_collect (GnmEvalPos const *ep, GnmValue const *value, void *closure) { gnm_float x = 0; collect_floats_t *cl = closure; gboolean ignore = FALSE; switch (value ? value->type : VALUE_EMPTY) { case VALUE_EMPTY: if (cl->flags & COLLECT_IGNORE_BLANKS) ignore = TRUE; else if (cl->flags & COLLECT_ZERO_BLANKS) x = 0; else return value_new_error_VALUE (ep); break; case VALUE_BOOLEAN: if (cl->flags & COLLECT_IGNORE_BOOLS) ignore = TRUE; else if (cl->flags & COLLECT_ZEROONE_BOOLS) x = value_get_as_float (value); else return value_new_error_VALUE (ep); break; case VALUE_CELLRANGE : case VALUE_ARRAY : /* Ranges and arrays are not singleton values treat as errors */ case VALUE_ERROR: if (cl->flags & COLLECT_IGNORE_ERRORS) ignore = TRUE; else if (cl->flags & COLLECT_ZERO_ERRORS) x = 0; else return value_new_error_VALUE (ep); break; case VALUE_FLOAT: x = value_get_as_float (value); break; case VALUE_STRING: if (cl->flags & COLLECT_COERCE_STRINGS) { GnmValue *vc = format_match_number (value_peek_string (value), NULL, cl->date_conv); gboolean bad = !vc || VALUE_IS_BOOLEAN (vc); if (vc) { x = value_get_as_float (vc); value_release (vc); } else x = 0; if (bad) return value_new_error_VALUE (ep); } else if (cl->flags & COLLECT_IGNORE_STRINGS) ignore = TRUE; else if (cl->flags & COLLECT_ZERO_STRINGS) x = 0; else return value_new_error_VALUE (ep); break; default: g_warning ("Trouble in callback_function_collect. (%d)", value->type); ignore = TRUE; } if (ignore) { if (cl->flags & COLLECT_INFO) cl->info = g_slist_prepend (cl->info, GUINT_TO_POINTER (cl->count)); else { return NULL; } } if (cl->count == cl->alloc_count) { cl->alloc_count = cl->alloc_count * 2 + 20; cl->data = g_renew (gnm_float, cl->data, cl->alloc_count); } cl->data[cl->count++] = x; return NULL; }
/** * 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)); }