1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * position.c: Utility routines for various types of positional
6 * Copyright (C) 2000-2005 Jody Goldberg (jody@gnome.org)
7 * Copyright (C) 2006-2009 Morten Welinder (terra@gnome.org)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
24 #include <gnumeric-config.h>
26 #include "libgnumeric.h"
30 #include "sheet-view.h"
37 /* GnmCellPos made a boxed type */
39 gnm_cell_pos_dup (GnmCellPos
*pos
)
41 GnmCellPos
*res
= g_new (GnmCellPos
, 1);
47 gnm_cell_pos_get_type (void)
52 t
= g_boxed_type_register_static ("GnmCellPos",
53 (GBoxedCopyFunc
)gnm_cell_pos_dup
,
54 (GBoxedFreeFunc
)g_free
);
59 /* GnmEvalPos made a boxed type */
61 gnm_eval_pos_dup (GnmEvalPos
*ep
)
63 GnmEvalPos
*res
= g_new0 (GnmEvalPos
, 1);
64 memcpy (res
, ep
, sizeof (GnmEvalPos
)); /* is this safe? */
69 gnm_eval_pos_get_type (void)
74 t
= g_boxed_type_register_static ("GnmEvalPos",
75 (GBoxedCopyFunc
)gnm_eval_pos_dup
,
76 (GBoxedFreeFunc
)g_free
);
83 * @ep: The position to init.
88 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
91 eval_pos_init (GnmEvalPos
*ep
, Sheet
*sheet
, int col
, int row
)
93 g_return_val_if_fail (ep
!= NULL
, NULL
);
94 g_return_val_if_fail (sheet
!= NULL
, NULL
);
100 ep
->array_texpr
= NULL
;
107 * @ep: The position to init.
111 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
114 eval_pos_init_pos (GnmEvalPos
*ep
, Sheet
*sheet
, GnmCellPos
const *pos
)
116 g_return_val_if_fail (ep
!= NULL
, NULL
);
117 g_return_val_if_fail (sheet
!= NULL
, NULL
);
118 g_return_val_if_fail (pos
!= NULL
, NULL
);
123 ep
->array_texpr
= NULL
;
130 * @ep: The position to init.
133 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
136 eval_pos_init_dep (GnmEvalPos
*ep
, GnmDependent
const *dep
)
138 g_return_val_if_fail (ep
!= NULL
, NULL
);
139 g_return_val_if_fail (dep
!= NULL
, NULL
);
141 ep
->eval
= *dependent_pos (dep
);
142 ep
->sheet
= dep
->sheet
;
143 ep
->dep
= (GnmDependent
*)dep
;
144 ep
->array_texpr
= NULL
;
150 * eval_pos_init_editpos:
151 * @ep: The position to init.
154 * The function initializes an evalpos with the edit position from the
156 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
159 eval_pos_init_editpos (GnmEvalPos
*ep
, SheetView
const *sv
)
161 g_return_val_if_fail (ep
!= NULL
, NULL
);
162 g_return_val_if_fail (GNM_IS_SV (sv
), NULL
);
164 return eval_pos_init (ep
, sv_sheet (sv
),
165 sv
->edit_pos
.col
, sv
->edit_pos
.row
);
169 * eval_pos_init_cell:
170 * @ep: The position to init.
173 * The function initializes an evalpos with the given cell
175 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
178 eval_pos_init_cell (GnmEvalPos
*ep
, GnmCell
const *cell
)
180 g_return_val_if_fail (ep
!= NULL
, NULL
);
181 g_return_val_if_fail (cell
!= NULL
, NULL
);
183 ep
->eval
= cell
->pos
;
184 ep
->sheet
= cell
->base
.sheet
;
185 ep
->dep
= (GnmDependent
*)GNM_CELL_TO_DEP (cell
);
186 ep
->array_texpr
= NULL
;
192 * eval_pos_init_sheet:
193 * @ep: The position to init.
196 * The function initializes an evalpos with the given sheet.
198 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
201 eval_pos_init_sheet (GnmEvalPos
*ep
, Sheet
const *sheet
)
203 g_return_val_if_fail (ep
!= NULL
, NULL
);
204 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
206 ep
->eval
.col
= ep
->eval
.row
= 0;
207 ep
->sheet
= (Sheet
*)sheet
;
209 ep
->array_texpr
= NULL
;
215 eval_pos_is_array_context (GnmEvalPos
const *ep
)
217 return ep
->array_texpr
!= NULL
;
222 gnm_parse_pos_dup (GnmParsePos
*ep
)
224 GnmParsePos
*res
= g_new0 (GnmParsePos
, 1);
225 memcpy (res
, ep
, sizeof (GnmParsePos
)); /* is this safe? */
230 gnm_parse_pos_get_type (void)
235 t
= g_boxed_type_register_static ("GnmParsePos",
236 (GBoxedCopyFunc
)gnm_parse_pos_dup
,
237 (GBoxedFreeFunc
)g_free
);
245 * @pp: The position to init.
246 * @sheet: The sheet being selected
247 * @wb: The workbook being selected.
251 * Use either a sheet (preferred) or a workbook to initialize the supplied
253 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
256 parse_pos_init (GnmParsePos
*pp
, Workbook
*wb
, Sheet
const *sheet
,
260 if (wb
== NULL
&& sheet
== NULL
)
263 g_return_val_if_fail (pp
!= NULL
, NULL
);
265 pp
->sheet
= (Sheet
*)sheet
;
266 pp
->wb
= sheet
? sheet
->workbook
: wb
;
274 * parse_pos_init_dep:
275 * @pp: The position to init.
276 * @dep: The dependent
278 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
281 parse_pos_init_dep (GnmParsePos
*pp
, GnmDependent
const *dep
)
283 g_return_val_if_fail (pp
!= NULL
, NULL
);
285 pp
->sheet
= dep
->sheet
;
286 pp
->wb
= dep
->sheet
? dep
->sheet
->workbook
: NULL
;
287 pp
->eval
= *dependent_pos (dep
);
293 * parse_pos_init_cell:
294 * @pp: The position to init.
297 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
300 parse_pos_init_cell (GnmParsePos
*pp
, GnmCell
const *cell
)
302 g_return_val_if_fail (cell
!= NULL
, NULL
);
303 g_return_val_if_fail (IS_SHEET (cell
->base
.sheet
), NULL
);
304 g_return_val_if_fail (cell
->base
.sheet
->workbook
!= NULL
, NULL
);
306 return parse_pos_init (pp
, NULL
, cell
->base
.sheet
,
307 cell
->pos
.col
, cell
->pos
.row
);
311 * parse_pos_init_evalpos:
312 * @pp: The position to init.
315 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
318 parse_pos_init_evalpos (GnmParsePos
*pp
, GnmEvalPos
const *ep
)
320 g_return_val_if_fail (ep
!= NULL
, NULL
);
322 return parse_pos_init (pp
, NULL
, ep
->sheet
, ep
->eval
.col
, ep
->eval
.row
);
326 * parse_pos_init_editpos:
327 * @pp: The position to init.
330 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
333 parse_pos_init_editpos (GnmParsePos
*pp
, SheetView
const *sv
)
335 g_return_val_if_fail (GNM_IS_SV (sv
), NULL
);
337 return parse_pos_init (pp
, NULL
, sv_sheet (sv
),
338 sv
->edit_pos
.col
, sv
->edit_pos
.row
);
342 * parse_pos_init_sheet:
343 * @pp: The position to init.
346 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
349 parse_pos_init_sheet (GnmParsePos
*pp
, Sheet
const *sheet
)
351 g_return_val_if_fail (pp
!= NULL
, NULL
);
352 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
353 return parse_pos_init (pp
, NULL
, sheet
, 0, 0);
356 /********************************************************************************/
360 gnm_cellref_dup (GnmCellRef
*ep
)
362 GnmCellRef
*res
= g_new0 (GnmCellRef
, 1);
363 memcpy (res
, ep
, sizeof (GnmCellRef
)); /* is this safe? */
368 gnm_cellref_get_type (void)
373 t
= g_boxed_type_register_static ("GnmCellRef",
374 (GBoxedCopyFunc
)gnm_cellref_dup
,
375 (GBoxedFreeFunc
)g_free
);
380 gnm_cellref_init (GnmCellRef
*ref
, Sheet
*sheet
, int col
, int row
, gboolean relative
)
385 ref
->col_relative
= ref
->row_relative
= relative
;
391 gnm_cellref_equal (GnmCellRef
const *a
, GnmCellRef
const *b
)
393 return (a
->col
== b
->col
) &&
394 (a
->col_relative
== b
->col_relative
) &&
395 (a
->row
== b
->row
) &&
396 (a
->row_relative
== b
->row_relative
) &&
397 (a
->sheet
== b
->sheet
);
401 gnm_cellref_hash (GnmCellRef
const *cr
)
404 h
= (h
<< 16) | (h
>> 16);
405 h
^= ((guint
)cr
->col
<< 2);
406 if (cr
->col_relative
) h
^= 1;
407 if (cr
->row_relative
) h
^= 2;
412 gnm_cellref_get_col (GnmCellRef
const *ref
, GnmEvalPos
const *ep
)
414 g_return_val_if_fail (ref
!= NULL
, 0);
415 g_return_val_if_fail (ep
!= NULL
, 0);
417 if (ref
->col_relative
) {
418 Sheet
const *sheet
= eval_sheet (ref
->sheet
, ep
->sheet
);
419 int res
= (ep
->eval
.col
+ ref
->col
) % gnm_sheet_get_max_cols (sheet
);
421 return res
+ gnm_sheet_get_max_cols (sheet
);
428 gnm_cellref_get_row (GnmCellRef
const *ref
, GnmEvalPos
const *ep
)
430 g_return_val_if_fail (ref
!= NULL
, 0);
431 g_return_val_if_fail (ep
!= NULL
, 0);
433 if (ref
->row_relative
) {
434 Sheet
const *sheet
= eval_sheet (ref
->sheet
, ep
->sheet
);
435 int res
= (ep
->eval
.row
+ ref
->row
) % gnm_sheet_get_max_rows (sheet
);
437 return res
+ gnm_sheet_get_max_rows (sheet
);
444 modulo (int i
, int max
)
458 gnm_cellpos_init_cellref_ss (GnmCellPos
*res
, GnmCellRef
const *cell_ref
,
459 GnmCellPos
const *pos
, GnmSheetSize
const *ss
)
461 g_return_if_fail (cell_ref
!= NULL
);
462 g_return_if_fail (res
!= NULL
);
464 if (cell_ref
->col_relative
) {
465 int col
= cell_ref
->col
+ pos
->col
;
466 res
->col
= modulo (col
, ss
->max_cols
);
468 res
->col
= cell_ref
->col
;
470 if (cell_ref
->row_relative
) {
471 int row
= cell_ref
->row
+ pos
->row
;
472 res
->row
= modulo (row
, ss
->max_rows
);
474 res
->row
= cell_ref
->row
;
478 gnm_cellpos_init_cellref (GnmCellPos
*res
, GnmCellRef
const *cell_ref
,
479 GnmCellPos
const *pos
, Sheet
const *base_sheet
)
481 Sheet
const *sheet
= eval_sheet (cell_ref
->sheet
, base_sheet
);
482 gnm_cellpos_init_cellref_ss (res
, cell_ref
, pos
,
483 gnm_sheet_get_size (sheet
));
487 gnm_cellref_make_abs (GnmCellRef
*dest
, GnmCellRef
const *src
, GnmEvalPos
const *ep
)
491 g_return_if_fail (dest
!= NULL
);
492 g_return_if_fail (src
!= NULL
);
493 g_return_if_fail (ep
!= NULL
);
495 gnm_cellpos_init_cellref (&pos
, src
, &ep
->eval
, ep
->sheet
);
497 dest
->sheet
= src
->sheet
;
500 dest
->col_relative
= FALSE
;
501 dest
->row_relative
= FALSE
;
505 gnm_cellref_set_col_ar (GnmCellRef
*cr
, GnmParsePos
const *pp
, gboolean abs_rel
)
507 if (cr
->col_relative
^ abs_rel
) {
508 if (cr
->col_relative
)
509 cr
->col
+= pp
->eval
.col
;
511 cr
->col
-= pp
->eval
.col
;
512 cr
->col_relative
= abs_rel
;
517 gnm_cellref_set_row_ar (GnmCellRef
*cr
, GnmParsePos
const *pp
, gboolean abs_rel
)
519 if (cr
->row_relative
^ abs_rel
) {
520 if (cr
->row_relative
)
521 cr
->row
+= pp
->eval
.row
;
523 cr
->row
-= pp
->eval
.row
;
524 cr
->row_relative
= abs_rel
;
529 gnm_rangeref_equal (GnmRangeRef
const *a
, GnmRangeRef
const *b
)
531 return gnm_cellref_equal (&a
->a
, &b
->a
) &&
532 gnm_cellref_equal (&a
->b
, &b
->b
);
536 gnm_rangeref_hash (GnmRangeRef
const *rr
)
538 guint h
= gnm_cellref_hash (&rr
->a
);
539 h
= (h
<< 16) | (h
>> 16);
540 h
^= gnm_cellref_hash (&rr
->b
);
545 gnm_rangeref_dup (GnmRangeRef
const *rr
)
549 g_return_val_if_fail (rr
!= NULL
, NULL
);
551 res
= g_new (GnmRangeRef
, 1);
557 gnm_rangeref_get_type (void)
562 t
= g_boxed_type_register_static ("GnmRangeRef",
563 (GBoxedCopyFunc
)gnm_rangeref_dup
,
564 (GBoxedFreeFunc
)g_free
);
570 gnm_rangeref_normalize_pp (GnmRangeRef
const *ref
, GnmParsePos
const *pp
,
571 Sheet
**start_sheet
, Sheet
**end_sheet
,
574 GnmSheetSize
const *ss
;
576 g_return_if_fail (ref
!= NULL
);
577 g_return_if_fail (pp
!= NULL
);
579 *start_sheet
= eval_sheet (ref
->a
.sheet
, pp
->sheet
);
580 *end_sheet
= eval_sheet (ref
->b
.sheet
, *start_sheet
);
582 ss
= gnm_sheet_get_size2 (*start_sheet
, pp
->wb
);
583 gnm_cellpos_init_cellref_ss (&dest
->start
, &ref
->a
, &pp
->eval
, ss
);
586 ? gnm_sheet_get_size (*end_sheet
)
588 gnm_cellpos_init_cellref_ss (&dest
->end
, &ref
->b
, &pp
->eval
, ss
);
590 range_normalize (dest
);
594 * gnm_rangeref_normalize:
596 * Take a range_ref and normalize it by converting to absolute coords and
597 * handling inversions.
600 gnm_rangeref_normalize (GnmRangeRef
const *ref
, GnmEvalPos
const *ep
,
601 Sheet
**start_sheet
, Sheet
**end_sheet
, GnmRange
*dest
)
605 parse_pos_init_evalpos (&pp
, ep
);
606 gnm_rangeref_normalize_pp (ref
, &pp
, start_sheet
, end_sheet
, dest
);
610 gnm_cellpos_hash (GnmCellPos
const *key
)
613 h
= (h
<< 16) | (h
>> 16);
619 gnm_cellpos_equal (GnmCellPos
const *a
, GnmCellPos
const *b
)
621 return (a
->row
== b
->row
&& a
->col
== b
->col
);