1
2 /*
3 * value-sheet.c: Utilies for sheet specific value handling
4 *
5 * Author:
6 * Miguel de Icaza (miguel@gnu.org).
7 */
8 #include <gnumeric-config.h>
9 #include <glib/gi18n-lib.h>
10 #include <gnumeric.h>
11
12 #include <value.h>
13 #include <gnm-format.h>
14 #include <ranges.h>
15 #include <sheet.h>
16 #include <cell.h>
17 #include <workbook.h>
18 #include <parse-util.h>
19 #include <goffice/goffice.h>
20
21 /* Debugging utility to print a GnmValue */
22 void
value_dump(GnmValue const * value)23 value_dump (GnmValue const *value)
24 {
25 switch (value->v_any.type){
26 case VALUE_EMPTY:
27 g_print ("EMPTY\n");
28 break;
29
30 case VALUE_ERROR:
31 g_print ("ERROR: %s\n", value->v_err.mesg->str);
32 break;
33
34 case VALUE_BOOLEAN:
35 g_print ("BOOLEAN: %s\n", go_locale_boolean_name (value->v_bool.val));
36 break;
37
38 case VALUE_STRING:
39 g_print ("STRING: %s\n", value->v_str.val->str);
40 break;
41
42 case VALUE_FLOAT:
43 g_print ("NUMBER: %" GNM_FORMAT_f "\n", value_get_as_float (value));
44 break;
45
46 case VALUE_ARRAY: {
47 int x, y;
48
49 g_print ("Array: { ");
50 for (y = 0; y < value->v_array.y; y++)
51 for (x = 0; x < value->v_array.x; x++)
52 value_dump (value->v_array.vals [x][y]);
53 g_print ("}\n");
54 break;
55 }
56 case VALUE_CELLRANGE: {
57 /*
58 * Do NOT normalize the ranges.
59 * Lets see them in their inverted glory if need be.
60 */
61 GnmCellRef const *c = &value->v_range.cell.a;
62 Sheet const *sheet = c->sheet;
63
64 g_print ("CellRange\n");
65 if (sheet && sheet->name_unquoted)
66 g_print ("%s:", sheet->name_quoted);
67 else if (sheet)
68 g_print ("%p :", (void *)sheet);
69 g_print ("%s%s%s%s\n",
70 (c->col_relative ? "":"$"), col_name(c->col),
71 (c->row_relative ? "":"$"), row_name(c->row));
72 c = &value->v_range.cell.b;
73 if (sheet && sheet->name_quoted)
74 g_print ("%s:", sheet->name_unquoted);
75 else if (sheet)
76 g_print ("%p :", (void *)sheet);
77 g_print ("%s%s%s%s\n",
78 (c->col_relative ? "":"$"), col_name(c->col),
79 (c->row_relative ? "":"$"), row_name(c->row));
80 break;
81 }
82 default:
83 g_print ("Unhandled item type\n");
84 }
85 }
86
87 int
value_area_get_width(GnmValue const * v,GnmEvalPos const * ep)88 value_area_get_width (GnmValue const *v, GnmEvalPos const *ep)
89 {
90 g_return_val_if_fail (v, 0);
91
92 if (VALUE_IS_CELLRANGE (v)) {
93 GnmRange r;
94 Sheet *start_sheet, *end_sheet;
95
96 g_return_val_if_fail (ep, 0);
97 gnm_rangeref_normalize (&v->v_range.cell, ep, &start_sheet, &end_sheet, &r);
98 return range_width (&r);
99 } else if (VALUE_IS_ARRAY (v))
100 return v->v_array.x;
101 return 1;
102 }
103
104 int
value_area_get_height(GnmValue const * v,GnmEvalPos const * ep)105 value_area_get_height (GnmValue const *v, GnmEvalPos const *ep)
106 {
107 g_return_val_if_fail (v, 0);
108
109 if (VALUE_IS_CELLRANGE (v)) {
110 GnmRange r;
111 Sheet *start_sheet, *end_sheet;
112
113 g_return_val_if_fail (ep, 0);
114 gnm_rangeref_normalize (&v->v_range.cell, ep, &start_sheet, &end_sheet, &r);
115 return range_height (&r);
116 } else if (VALUE_IS_ARRAY (v))
117 return v->v_array.y;
118 return 1;
119 }
120
121 /**
122 * value_area_fetch_x_y:
123 * @v: const #GnmValue *
124 * @x: column
125 * @y: row
126 * @ep: const #GnmEvalPos *
127 *
128 * An internal routine to get a cell from an array or range.
129 * Ensures that elements of CELLRANGE are evaluated
130 *
131 * Returns the element if it exists and is non-empty otherwise returns 0
132 **/
133 GnmValue const *
value_area_fetch_x_y(GnmValue const * v,int x,int y,GnmEvalPos const * ep)134 value_area_fetch_x_y (GnmValue const *v, int x, int y, GnmEvalPos const *ep)
135 {
136 GnmValue const * const res = value_area_get_x_y (v, x, y, ep);
137 if (VALUE_IS_EMPTY (res))
138 return value_zero;
139 else
140 return res;
141 }
142
143 /**
144 * value_area_get_x_y:
145 * @v: const #GnmValue *
146 * @x: column
147 * @y: row
148 * @ep: const #GnmEvalPos *
149 *
150 * An internal routine to get a cell from an array or range.
151 * Ensures that elements of CELLRANGE are evaluated
152 *
153 * If any problems occur a NULL is returned.
154 **/
155 GnmValue const *
value_area_get_x_y(GnmValue const * v,int x,int y,GnmEvalPos const * ep)156 value_area_get_x_y (GnmValue const *v, int x, int y, GnmEvalPos const *ep)
157 {
158 g_return_val_if_fail (v, NULL);
159
160 if (VALUE_IS_ARRAY (v)){
161 g_return_val_if_fail (x < v->v_array.x &&
162 y < v->v_array.y,
163 NULL);
164 return v->v_array.vals [x][y];
165 } else if (VALUE_IS_CELLRANGE (v)) {
166 GnmRange r;
167 Sheet *start_sheet, *end_sheet;
168 GnmCell *cell;
169
170 gnm_rangeref_normalize (&v->v_range.cell, ep,
171 &start_sheet, &end_sheet,
172 &r);
173 if (start_sheet != end_sheet)
174 return NULL;
175
176 // Full wrap-around
177 x = (r.start.col + x) % gnm_sheet_get_max_cols (start_sheet);
178 y = (r.start.row + y) % gnm_sheet_get_max_rows (start_sheet);
179
180 /* Speedup */
181 if (start_sheet->cols.max_used < x ||
182 start_sheet->rows.max_used < y)
183 return value_new_empty ();
184
185 cell = sheet_cell_get (start_sheet, x, y);
186 if (cell != NULL) {
187 gnm_cell_eval (cell);
188 return cell->value;
189 }
190
191 return value_new_empty ();
192 } else
193 return v;
194 }
195
196 typedef struct {
197 GnmValueIter v_iter;
198 GnmValueIterFunc func;
199 int base_col, base_row;
200 gpointer user_data;
201 } WrapperClosure;
202
203 static GnmValue *
cb_wrapper_foreach_cell_in_area(GnmCellIter const * iter,WrapperClosure * wrap)204 cb_wrapper_foreach_cell_in_area (GnmCellIter const *iter, WrapperClosure *wrap)
205 {
206 if (iter->cell != NULL) {
207 gnm_cell_eval (iter->cell);
208 wrap->v_iter.v = iter->cell->value;
209 } else
210 wrap->v_iter.v = NULL;
211 wrap->v_iter.x = iter->pp.eval.col - wrap->base_col;
212 wrap->v_iter.y = iter->pp.eval.row - wrap->base_row;
213 wrap->v_iter.cell_iter = iter;
214 return (*wrap->func) (&wrap->v_iter, wrap->user_data);
215 }
216
217 /**
218 * value_area_foreach:
219 * @v: const #GnmValue
220 * @ep: const #GnmEvalPos
221 * @flags: #CellIterFlags
222 * @func: (scope call): #GnmValueIterFunc
223 * @user_data:
224 *
225 * For each existing element in an array or range , invoke the
226 * callback routine.
227 *
228 * Returns:
229 * non-%NULL on error, or VALUE_TERMINATE if some the handler requested
230 * to stop (by returning non-%NULL).
231 **/
232 GnmValue *
value_area_foreach(GnmValue const * v,GnmEvalPos const * ep,CellIterFlags flags,GnmValueIterFunc func,gpointer user_data)233 value_area_foreach (GnmValue const *v, GnmEvalPos const *ep,
234 CellIterFlags flags,
235 GnmValueIterFunc func,
236 gpointer user_data)
237 {
238 GnmValueIter v_iter;
239 GnmValue *tmp;
240
241 g_return_val_if_fail (func != NULL, NULL);
242
243 if (VALUE_IS_CELLRANGE (v)) {
244 WrapperClosure wrap;
245 GnmRange r;
246 Sheet *start_sheet, *end_sheet;
247
248 gnm_rangeref_normalize (&v->v_range.cell, ep, &start_sheet, &end_sheet, &r);
249
250 wrap.v_iter.ep = ep;
251 wrap.v_iter.region = v;
252 wrap.func = func;
253 wrap.user_data = user_data;
254 wrap.base_col = r.start.col;
255 wrap.base_row = r.start.row;
256 return workbook_foreach_cell_in_range (ep, v, flags,
257 (CellIterFunc) cb_wrapper_foreach_cell_in_area, &wrap);
258 }
259
260 v_iter.ep = ep;
261 v_iter.region = v;
262 v_iter.cell_iter = NULL;
263
264 /* If not an array, apply func to singleton */
265 if (!VALUE_IS_ARRAY (v)) {
266 v_iter.x = v_iter.y = 0;
267 v_iter.v = v;
268 return (*func) (&v_iter, user_data);
269 }
270
271 for (v_iter.x = v->v_array.x; v_iter.x-- > 0;)
272 for (v_iter.y = v->v_array.y; v_iter.y-- > 0;) {
273 v_iter.v = v->v_array.vals [v_iter.x][v_iter.y];
274 if ((tmp = (*func)(&v_iter, user_data)) != NULL)
275 return tmp;
276 }
277
278 return NULL;
279 }
280