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