Introspection fixes.
[gnumeric.git] / src / position.c
bloba5d07145ee9f958874eea1ade200de857ee732f8
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * position.c: Utility routines for various types of positional
4 * coordinates.
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
22 * USA
24 #include <gnumeric-config.h>
25 #include "gnumeric.h"
26 #include "libgnumeric.h"
27 #include "position.h"
29 #include "sheet.h"
30 #include "sheet-view.h"
31 #include "cell.h"
32 #include "value.h"
33 #include "ranges.h"
34 #include <string.h>
35 #include "workbook.h"
37 /* GnmCellPos made a boxed type */
38 static GnmCellPos *
39 gnm_cell_pos_dup (GnmCellPos *pos)
41 GnmCellPos *res = g_new (GnmCellPos, 1);
42 *res = *pos;
43 return res;
46 GType
47 gnm_cell_pos_get_type (void)
49 static GType t = 0;
51 if (t == 0) {
52 t = g_boxed_type_register_static ("GnmCellPos",
53 (GBoxedCopyFunc)gnm_cell_pos_dup,
54 (GBoxedFreeFunc)g_free);
56 return t;
59 /* GnmEvalPos made a boxed type */
60 static GnmEvalPos *
61 gnm_eval_pos_dup (GnmEvalPos *ep)
63 GnmEvalPos *res = g_new0 (GnmEvalPos, 1);
64 memcpy (res, ep, sizeof (GnmEvalPos)); /* is this safe? */
65 return res;
68 GType
69 gnm_eval_pos_get_type (void)
71 static GType t = 0;
73 if (t == 0) {
74 t = g_boxed_type_register_static ("GnmEvalPos",
75 (GBoxedCopyFunc)gnm_eval_pos_dup,
76 (GBoxedFreeFunc)g_free);
78 return t;
81 /**
82 * eval_pos_init:
83 * @ep: The position to init.
84 * @s: #Sheet
85 * @col: column.
86 * @row: row
88 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
89 **/
90 GnmEvalPos *
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);
96 ep->eval.col = col;
97 ep->eval.row = row;
98 ep->sheet = sheet;
99 ep->dep = NULL;
100 ep->array_texpr = NULL;
102 return ep;
106 * eval_pos_init_pos:
107 * @ep: The position to init.
108 * @s: #Sheet
109 * @pos: #GnmCellPos
111 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
113 GnmEvalPos *
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);
120 ep->eval = *pos;
121 ep->sheet = sheet;
122 ep->dep = NULL;
123 ep->array_texpr = NULL;
125 return ep;
129 * eval_pos_init_dep:
130 * @ep: The position to init.
131 * @dep:
133 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
135 GnmEvalPos *
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;
146 return ep;
150 * eval_pos_init_editpos:
151 * @ep: The position to init.
152 * @sv: @Sheetview
154 * The function initializes an evalpos with the edit position from the
155 * given sheetview.
156 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
158 GnmEvalPos *
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.
171 * @cell: A cell
173 * The function initializes an evalpos with the given cell
175 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
177 GnmEvalPos *
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;
188 return ep;
192 * eval_pos_init_sheet:
193 * @ep: The position to init.
194 * @sheet: A sheet
196 * The function initializes an evalpos with the given sheet.
198 * Returns: (transfer none): the initialized #GnmEvalPos (@ep).
200 GnmEvalPos *
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;
208 ep->dep = NULL;
209 ep->array_texpr = NULL;
211 return ep;
214 gboolean
215 eval_pos_is_array_context (GnmEvalPos const *ep)
217 return ep->array_texpr != NULL;
221 static GnmParsePos *
222 gnm_parse_pos_dup (GnmParsePos *ep)
224 GnmParsePos *res = g_new0 (GnmParsePos, 1);
225 memcpy (res, ep, sizeof (GnmParsePos)); /* is this safe? */
226 return res;
229 GType
230 gnm_parse_pos_get_type (void)
232 static GType t = 0;
234 if (t == 0) {
235 t = g_boxed_type_register_static ("GnmParsePos",
236 (GBoxedCopyFunc)gnm_parse_pos_dup,
237 (GBoxedFreeFunc)g_free);
239 return t;
243 * parse_pos_init:
245 * @pp: The position to init.
246 * @sheet: The sheet being selected
247 * @wb: The workbook being selected.
248 * @row:
249 * @col:
251 * Use either a sheet (preferred) or a workbook to initialize the supplied
252 * ParsePosition.
253 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
255 GnmParsePos *
256 parse_pos_init (GnmParsePos *pp, Workbook *wb, Sheet const *sheet,
257 int col, int row)
259 /* Global */
260 if (wb == NULL && sheet == NULL)
261 return NULL;
263 g_return_val_if_fail (pp != NULL, NULL);
265 pp->sheet = (Sheet *)sheet;
266 pp->wb = sheet ? sheet->workbook : wb;
267 pp->eval.col = col;
268 pp->eval.row = row;
270 return pp;
274 * parse_pos_init_dep:
275 * @pp: The position to init.
276 * @dep: The dependent
278 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
280 GnmParsePos *
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);
289 return pp;
293 * parse_pos_init_cell:
294 * @pp: The position to init.
295 * @cell: The cell
297 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
299 GnmParsePos *
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.
313 * @ep: #GnmEvalPos
315 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
317 GnmParsePos *
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.
328 * @sv: sheet view
330 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
332 GnmParsePos *
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.
344 * @sheet: The sheet
346 * Returns: (transfer none): the initialized #GnmParsePos (@pp).
348 GnmParsePos *
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 /********************************************************************************/
359 static GnmCellRef *
360 gnm_cellref_dup (GnmCellRef *ep)
362 GnmCellRef *res = g_new0 (GnmCellRef, 1);
363 memcpy (res, ep, sizeof (GnmCellRef)); /* is this safe? */
364 return res;
367 GType
368 gnm_cellref_get_type (void)
370 static GType t = 0;
372 if (t == 0) {
373 t = g_boxed_type_register_static ("GnmCellRef",
374 (GBoxedCopyFunc)gnm_cellref_dup,
375 (GBoxedFreeFunc)g_free);
377 return t;
379 GnmCellRef *
380 gnm_cellref_init (GnmCellRef *ref, Sheet *sheet, int col, int row, gboolean relative)
382 ref->sheet = sheet;
383 ref->col = col;
384 ref->row = row;
385 ref->col_relative = ref->row_relative = relative;
387 return ref;
390 gboolean
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);
400 guint
401 gnm_cellref_hash (GnmCellRef const *cr)
403 guint h = cr->row;
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;
408 return h;
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);
420 if (res < 0)
421 return res + gnm_sheet_get_max_cols (sheet);
422 return res;
424 return ref->col;
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);
436 if (res < 0)
437 return res + gnm_sheet_get_max_rows (sheet);
438 return res;
440 return ref->row;
443 static int
444 modulo (int i, int max)
446 if (i < 0) {
447 i %= max;
448 if (i < 0)
449 i += max;
450 } else if (i >= max)
451 i %= max;
453 return i;
457 void
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);
467 } else
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);
473 } else
474 res->row = cell_ref->row;
477 void
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));
486 void
487 gnm_cellref_make_abs (GnmCellRef *dest, GnmCellRef const *src, GnmEvalPos const *ep)
489 GnmCellPos pos;
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;
498 dest->col = pos.col;
499 dest->row = pos.row;
500 dest->col_relative = FALSE;
501 dest->row_relative = FALSE;
504 void
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;
510 else
511 cr->col -= pp->eval.col;
512 cr->col_relative = abs_rel;
516 void
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;
522 else
523 cr->row -= pp->eval.row;
524 cr->row_relative = abs_rel;
528 gboolean
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);
535 guint
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);
541 return h;
544 GnmRangeRef *
545 gnm_rangeref_dup (GnmRangeRef const *rr)
547 GnmRangeRef *res;
549 g_return_val_if_fail (rr != NULL, NULL);
551 res = g_new (GnmRangeRef, 1);
552 *res = *rr;
553 return res;
556 GType
557 gnm_rangeref_get_type (void)
559 static GType t = 0;
561 if (t == 0) {
562 t = g_boxed_type_register_static ("GnmRangeRef",
563 (GBoxedCopyFunc)gnm_rangeref_dup,
564 (GBoxedFreeFunc)g_free);
566 return t;
569 void
570 gnm_rangeref_normalize_pp (GnmRangeRef const *ref, GnmParsePos const *pp,
571 Sheet **start_sheet, Sheet **end_sheet,
572 GnmRange *dest)
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);
585 ss = *end_sheet
586 ? gnm_sheet_get_size (*end_sheet)
587 : ss;
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.
599 void
600 gnm_rangeref_normalize (GnmRangeRef const *ref, GnmEvalPos const *ep,
601 Sheet **start_sheet, Sheet **end_sheet, GnmRange *dest)
603 GnmParsePos pp;
605 parse_pos_init_evalpos (&pp, ep);
606 gnm_rangeref_normalize_pp (ref, &pp, start_sheet, end_sheet, dest);
609 guint
610 gnm_cellpos_hash (GnmCellPos const *key)
612 guint h = key->row;
613 h = (h << 16) | (h >> 16);
614 h ^= key->col;
615 return h;
618 gint
619 gnm_cellpos_equal (GnmCellPos const *a, GnmCellPos const *b)
621 return (a->row == b->row && a->col == b->col);