Update Spanish translation
[gnumeric.git] / src / parse-util.c
blobeea086ce81722314fcdb9fe25b8c08fbd3bebcbf
1 /*
2 * parse-util.c: Various utility routines to parse or produce
3 * string representations of common reference types.
5 * Copyright (C) 2000-2007 Jody Goldberg (jody@gnome.org)
6 * Copyright (C) 2008-2009 Morten Welinder (terra@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 * USA
23 #include <gnumeric-config.h>
24 #include <gnumeric.h>
25 #include <parse-util.h>
27 #include <application.h>
28 #include <workbook.h>
29 #include <sheet.h>
30 #include <value.h>
31 #include <ranges.h>
32 #include <cell.h>
33 #include <expr.h>
34 #include <number-match.h>
35 #include <gnm-format.h>
36 #include <expr-name.h>
37 #include <func.h>
38 #include <mstyle.h>
39 #include <sheet-style.h>
40 /* For std_expr_name_handler: */
41 #include <expr-impl.h>
42 #include <gutils.h>
43 #include <goffice/goffice.h>
45 #include <errno.h>
46 #include <stdlib.h>
47 #include <glib.h>
48 #include <string.h>
50 static GnmLexerItem *
51 gnm_lexer_item_copy (GnmLexerItem *li)
53 return g_memdup (li, sizeof (*li));
56 GType
57 gnm_lexer_item_get_type (void)
59 static GType t = 0;
61 if (t == 0) {
62 t = g_boxed_type_register_static ("GnmLexerItem",
63 (GBoxedCopyFunc)gnm_lexer_item_copy,
64 (GBoxedFreeFunc)g_free);
66 return t;
69 static void
70 col_name_internal (GString *target, int col)
72 static int const steps[] = {
73 26,
74 26 * 26,
75 26 * 26 * 26,
76 26 * 26 * 26 * 26,
77 26 * 26 * 26 * 26 * 26,
78 26 * 26 * 26 * 26 * 26 * 26,
79 INT_MAX
81 int i;
82 char *dst;
84 if (col < 0) {
85 /* Invalid column. */
86 g_string_append_printf (target, "[C%d]", col);
87 return;
90 for (i = 0; col >= steps[i]; i++)
91 col -= steps[i];
93 g_string_set_size (target, target->len + (i + 1));
94 dst = target->str + target->len;
95 while (i-- >= 0) {
96 *--dst = 'A' + col % 26;
97 col /= 26;
102 * col_name: (skip)
103 * @col: column number
105 * Returns: (transfer none): A string representation of @col
107 char const *
108 col_name (int col)
110 static GString *buffer = NULL;
111 if (!buffer)
112 buffer = g_string_new (NULL);
113 g_string_truncate (buffer, 0);
115 col_name_internal (buffer, col);
117 return buffer->str;
121 * cols_name: (skip)
122 * @start_col: column number
123 * @end_col: column number
125 * Returns: (transfer none): A string representation of the columns from
126 * @start_col to @end_col.
128 char const *
129 cols_name (int start_col, int end_col)
131 static GString *buffer = NULL;
132 if (!buffer)
133 buffer = g_string_new (NULL);
134 g_string_truncate (buffer, 0);
136 col_name_internal (buffer, start_col);
137 if (start_col != end_col) {
138 g_string_append_c (buffer, ':');
139 col_name_internal (buffer, end_col);
142 return buffer->str;
146 * col_parse: (skip)
148 * Returns: (transfer none):
150 char const *
151 col_parse (char const *str, GnmSheetSize const *ss,
152 int *res, unsigned char *relative)
154 char const *ptr, *start = str;
155 int col = -1;
156 int max = ss->max_cols;
158 if (!(*relative = (*start != '$')))
159 start++;
161 for (ptr = start; col < max ; ptr++)
162 if (('a' <= *ptr && *ptr <= 'z'))
163 col = 26 * (col + 1) + (*ptr - 'a');
164 else if (('A' <= *ptr && *ptr <= 'Z'))
165 col = 26 * (col + 1) + (*ptr - 'A');
166 else if (ptr != start) {
167 *res = col;
168 return ptr;
169 } else
170 return NULL;
171 return NULL;
174 /***************************************************************************/
176 static void
177 row_name_internal (GString *target, int row)
179 g_string_append_printf (target, "%d", row + 1);
183 * row_name: (skip)
184 * @row: row number
186 * Returns: (transfer none): A string representation of @row
188 char const *
189 row_name (int row)
191 static GString *buffer = NULL;
192 if (!buffer)
193 buffer = g_string_new (NULL);
194 g_string_truncate (buffer, 0);
196 row_name_internal (buffer, row);
198 return buffer->str;
202 * rows_name: (skip)
203 * @start_row: row number
204 * @end_row: row number
206 * Returns: (transfer none): A string representation of the rows from
207 * @start_row to @end_row.
209 char const *
210 rows_name (int start_row, int end_row)
212 static GString *buffer = NULL;
213 if (!buffer)
214 buffer = g_string_new (NULL);
215 g_string_truncate (buffer, 0);
217 row_name_internal (buffer, start_row);
218 if (start_row != end_row) {
219 g_string_append_c (buffer, ':');
220 row_name_internal (buffer, end_row);
223 return buffer->str;
227 * row_parse: (skip)
229 * Returns: (transfer none):
231 char const *
232 row_parse (char const *str, GnmSheetSize const *ss,
233 int *res, unsigned char *relative)
235 char const *end, *ptr = str;
236 long int row;
237 int max = ss->max_rows;
239 if (!(*relative = (*ptr != '$')))
240 ptr++;
242 /* Initial '0' is not allowed. */
243 if (*ptr <= '0' || *ptr > '9')
244 return NULL;
247 * Do not allow letters after the row number. If we did, then
248 * the name "K3P" would lex as the reference K3 followed by the
249 * name "P".
251 row = strtol (ptr, (char **)&end, 10);
252 if (ptr != end &&
253 !g_unichar_isalnum (g_utf8_get_char (end)) && *end != '_' &&
254 0 < row && row <= max) {
255 *res = row - 1;
256 return end;
257 } else
258 return NULL;
261 /***************************************************************************/
263 static void
264 r1c1_add_index (GString *target, char type, int num, unsigned char relative)
266 if (relative) {
267 if (num != 0)
268 g_string_append_printf (target, "%c[%d]", type, num);
269 else
270 g_string_append_c (target, type);
271 } else
272 g_string_append_printf (target, "%c%d", type, num + 1);
275 static char *
276 wb_rel_uri (Workbook *wb, Workbook *ref_wb)
278 char const *uri = go_doc_get_uri ((GODoc *)wb);
279 char const *ref_uri = go_doc_get_uri ((GODoc *)ref_wb);
280 char *rel_uri = go_url_make_relative (uri, ref_uri);
282 if (rel_uri == NULL || rel_uri[0] == '/') {
283 g_free (rel_uri);
284 return g_strdup (uri);
287 return rel_uri;
291 * cellref_as_string: (skip)
292 * @out: #GnmConventionsOut
293 * @cell_ref:
294 * @no_sheetname: If %TRUE, suppress sheet name
296 * Emits a string containing representation of @ref as evaluated at @pp.
297 * @no_sheetname can be used to suppress the addition of the sheetname
298 * for non-local references.
300 void
301 cellref_as_string (GnmConventionsOut *out,
302 GnmCellRef const *cell_ref,
303 gboolean no_sheetname)
305 GString *target = out->accum;
306 Sheet const *sheet = cell_ref->sheet;
308 /* If it is a non-local reference, add the path to the external sheet */
309 if (sheet != NULL && !no_sheetname) {
310 if (out->pp->wb == NULL && out->pp->sheet == NULL)
311 /* For the expression leak printer. */
312 g_string_append (target, "'?'");
313 else if (NULL == out->pp->wb || sheet->workbook == out->pp->wb)
314 g_string_append (target, sheet->name_quoted);
315 else {
316 char *rel_uri = wb_rel_uri (sheet->workbook, out->pp->wb);
317 g_string_append_c (target, '[');
318 g_string_append (target, rel_uri);
319 g_string_append_c (target, ']');
320 g_string_append (target, sheet->name_quoted);
321 g_free (rel_uri);
323 g_string_append_unichar (target, out->convs->sheet_name_sep);
326 if (out->convs->r1c1_addresses) { /* R1C1 handler */
327 r1c1_add_index (target, 'R', cell_ref->row, cell_ref->row_relative);
328 r1c1_add_index (target, 'C', cell_ref->col, cell_ref->col_relative);
329 } else {
330 GnmCellPos pos;
331 Sheet const *size_sheet = eval_sheet (sheet, out->pp->sheet);
332 GnmSheetSize const *ss =
333 gnm_sheet_get_size2 (size_sheet, out->pp->wb);
335 gnm_cellpos_init_cellref_ss (&pos, cell_ref, &out->pp->eval, ss);
337 if (!cell_ref->col_relative)
338 g_string_append_c (target, '$');
339 col_name_internal (target, pos.col);
341 if (!cell_ref->row_relative)
342 g_string_append_c (target, '$');
343 row_name_internal (target, pos.row);
348 * rangeref_as_string: (skip)
349 * @out: #GnmConventionsOut
350 * @ref: #GnmRangeRef
353 void
354 rangeref_as_string (GnmConventionsOut *out, GnmRangeRef const *ref)
356 GnmRange r;
357 GString *target = out->accum;
358 Sheet *start_sheet, *end_sheet;
359 GnmSheetSize const *end_ss;
361 gnm_rangeref_normalize_pp (ref, out->pp, &start_sheet, &end_sheet, &r);
363 end_ss = gnm_sheet_get_size2 (end_sheet, out->pp->wb);
365 if (ref->a.sheet) {
366 if (NULL != out->pp->wb && ref->a.sheet->workbook != out->pp->wb) {
367 char *rel_uri = wb_rel_uri (ref->a.sheet->workbook, out->pp->wb);
368 g_string_append_c (target, '[');
369 g_string_append (target, rel_uri);
370 g_string_append_c (target, ']');
371 g_free (rel_uri);
373 if (out->pp->wb == NULL && out->pp->sheet == NULL)
374 /* For the expression leak printer. */
375 g_string_append (target, "'?'");
376 else if (ref->b.sheet == NULL || ref->a.sheet == ref->b.sheet)
377 g_string_append (target, ref->a.sheet->name_quoted);
378 else {
379 g_string_append (target, ref->a.sheet->name_quoted);
380 g_string_append_c (target, ':');
381 g_string_append (target, ref->b.sheet->name_quoted);
383 g_string_append_unichar (target, out->convs->sheet_name_sep);
386 if (out->convs->r1c1_addresses) { /* R1C1 handler */
387 /* be sure to use else if so that a1:iv65535 does not vanish */
388 if (r.start.col == 0 && r.end.col == end_ss->max_cols - 1) {
389 r1c1_add_index (target, 'R', ref->a.row, ref->a.row_relative);
390 if (ref->a.row != ref->b.row ||
391 ref->a.row_relative != ref->b.row_relative) {
392 g_string_append_c (target, ':');
393 r1c1_add_index (target, 'R', ref->b.row, ref->b.row_relative);
395 } else if (r.start.row == 0 && r.end.row == end_ss->max_rows - 1) {
396 r1c1_add_index (target, 'C', ref->a.col, ref->a.col_relative);
397 if (ref->a.col != ref->b.col ||
398 ref->a.col_relative != ref->b.col_relative) {
399 g_string_append_c (target, ':');
400 r1c1_add_index (target, 'C', ref->b.col, ref->b.col_relative);
402 } else {
403 r1c1_add_index (target, 'R', ref->a.row, ref->a.row_relative);
404 r1c1_add_index (target, 'C', ref->a.col, ref->a.col_relative);
405 if (r.start.col != r.end.col ||
406 ref->a.col_relative != ref->b.col_relative ||
407 r.start.row != r.end.row ||
408 ref->a.row_relative != ref->b.row_relative) {
409 g_string_append_c (target, ':');
410 r1c1_add_index (target, 'R', ref->b.row, ref->b.row_relative);
411 r1c1_add_index (target, 'C', ref->b.col, ref->b.col_relative);
414 } else {
415 /* be sure to use else if so that a1:iv65535 does not vanish */
416 if (r.start.col == 0 && r.end.col == end_ss->max_cols - 1) {
417 if (!ref->a.row_relative)
418 g_string_append_c (target, '$');
419 row_name_internal (target, r.start.row);
420 g_string_append_c (target, ':');
421 if (!ref->b.row_relative)
422 g_string_append_c (target, '$');
423 row_name_internal (target, r.end.row);
424 } else if (r.start.row == 0 && r.end.row == end_ss->max_rows - 1) {
425 if (!ref->a.col_relative)
426 g_string_append_c (target, '$');
427 col_name_internal (target, r.start.col);
428 g_string_append_c (target, ':');
429 if (!ref->b.col_relative)
430 g_string_append_c (target, '$');
431 col_name_internal (target, r.end.col);
432 } else {
433 if (!ref->a.col_relative)
434 g_string_append_c (target, '$');
435 col_name_internal (target, r.start.col);
436 if (!ref->a.row_relative)
437 g_string_append_c (target, '$');
438 row_name_internal (target, r.start.row);
440 if (r.start.col != r.end.col ||
441 ref->a.col_relative != ref->b.col_relative ||
442 r.start.row != r.end.row ||
443 ref->a.row_relative != ref->b.row_relative) {
444 g_string_append_c (target, ':');
445 if (!ref->b.col_relative)
446 g_string_append_c (target, '$');
447 col_name_internal (target, r.end.col);
448 if (!ref->b.row_relative)
449 g_string_append_c (target, '$');
450 row_name_internal (target, r.end.row);
457 * gnm_1_0_rangeref_as_string: (skip)
458 * @out: #GnmConventionsOut
459 * @ref: #GnmRangeRef
461 * Simplified variant of rangeref_as_string that old versions of gnumeric can
462 * read. It drops support for full col/row references. We can remap them on
463 * import.
465 * This function also ignores R1C1 settings.
467 void
468 gnm_1_0_rangeref_as_string (GnmConventionsOut *out, GnmRangeRef const *ref)
470 GnmRange r;
471 GString *target = out->accum;
472 Sheet *start_sheet, *end_sheet;
474 gnm_rangeref_normalize_pp (ref, out->pp, &start_sheet, &end_sheet, &r);
476 if (ref->a.sheet) {
477 if (NULL != out->pp->wb && ref->a.sheet->workbook != out->pp->wb) {
478 char *rel_uri = wb_rel_uri (ref->a.sheet->workbook, out->pp->wb);
479 g_string_append_c (target, '[');
480 g_string_append (target, rel_uri);
481 g_string_append_c (target, ']');
482 g_free (rel_uri);
484 if (out->pp->wb == NULL && out->pp->sheet == NULL)
485 /* For the expression leak printer. */
486 g_string_append (target, "'?'");
487 else if (ref->b.sheet == NULL || ref->a.sheet == ref->b.sheet)
488 g_string_append (target, ref->a.sheet->name_quoted);
489 else {
490 g_string_append (target, ref->a.sheet->name_quoted);
491 g_string_append_c (target, ':');
492 g_string_append (target, ref->b.sheet->name_quoted);
494 g_string_append_unichar (target, out->convs->sheet_name_sep);
497 if (!ref->a.col_relative)
498 g_string_append_c (target, '$');
499 col_name_internal (target, r.start.col);
500 if (!ref->a.row_relative)
501 g_string_append_c (target, '$');
502 row_name_internal (target, r.start.row);
504 if (r.start.col != r.end.col ||
505 ref->a.col_relative != ref->b.col_relative ||
506 r.start.row != r.end.row ||
507 ref->a.row_relative != ref->b.row_relative) {
508 g_string_append_c (target, ':');
509 if (!ref->b.col_relative)
510 g_string_append_c (target, '$');
511 col_name_internal (target, r.end.col);
512 if (!ref->b.row_relative)
513 g_string_append_c (target, '$');
514 row_name_internal (target, r.end.row);
518 static char const *
519 cellref_a1_get (GnmCellRef *out, GnmSheetSize const *ss,
520 char const *in, GnmCellPos const *pos)
522 int col;
523 int row;
525 g_return_val_if_fail (in != NULL, NULL);
526 g_return_val_if_fail (out != NULL, NULL);
528 in = col_parse (in, ss, &col, &out->col_relative);
529 if (!in)
530 return NULL;
532 in = row_parse (in, ss, &row, &out->row_relative);
533 if (!in)
534 return NULL;
536 /* Setup the cell reference information */
537 if (out->row_relative)
538 out->row = row - pos->row;
539 else
540 out->row = row;
542 if (out->col_relative)
543 out->col = col - pos->col;
544 else
545 out->col = col;
547 out->sheet = NULL;
549 return in;
552 /* skip first character (which was R or C) */
553 static char const *
554 r1c1_get_index (char const *str, GnmSheetSize const *ss,
555 int *num, unsigned char *relative, gboolean is_col)
557 char *end;
558 long l;
559 int max = is_col ? ss->max_cols : ss->max_rows;
561 if (str[0] == '\0')
562 return NULL;
564 str++;
565 *relative = (*str == '[');
566 if (*relative)
567 str++;
568 else if (*str == '-' || *str == '+') { /* handle RC-10 as RC followed by -10 */
569 *relative = TRUE;
570 *num = 0;
571 return str;
574 errno = 0;
575 *num = l = strtol (str, &end, 10);
576 if (errno == ERANGE || l <= G_MININT || l > G_MAXINT) {
577 /* Note: this includes G_MININT to avoid negation overflow. */
578 return NULL;
580 if (str == end) {
581 if (*relative)
582 return NULL;
583 *relative = TRUE;
584 *num = 0;
585 } else if (*relative) {
586 if (*end != ']')
587 return NULL;
588 *num = (*num > 0
589 ? *num % max
590 : -(-*num % max));
591 return end + 1;
592 } else {
593 if (*num <= 0 || *num > max)
594 return NULL;
595 (*num)--;
597 return end;
600 static char const *
601 cellref_r1c1_get (GnmCellRef *out, GnmSheetSize const *ss,
602 char const *in, GnmCellPos const *pos)
604 out->sheet = NULL;
605 if (*in != 'R' && *in != 'r')
606 return NULL;
607 if (NULL == (in = r1c1_get_index (in, ss,
608 &out->row, &out->row_relative,
609 FALSE)))
610 return NULL;
611 if (*in != 'C' && *in != 'c')
612 return NULL;
613 if (NULL == (in = r1c1_get_index (in, ss,
614 &out->col, &out->col_relative,
615 TRUE)))
616 return NULL;
617 if (g_ascii_isalpha (*in))
618 return NULL;
619 return in;
623 * cellref_parse: (skip)
624 * @out: (out): destination GnmCellRef
625 * @ss: size of the sheet where parsing is being done
626 * @in: reference description text, no leading whitespace allowed.
627 * @pos: position parsing is being done at
629 * Converts the string representation of a #GnmCellRef into
630 * an internal representation.
632 * Returns: (transfer none): a pointer to the character following the
633 * cellref.
635 char const *
636 cellref_parse (GnmCellRef *out, GnmSheetSize const *ss,
637 char const *in, GnmCellPos const *pos)
639 char const *res;
641 g_return_val_if_fail (in != NULL, NULL);
642 g_return_val_if_fail (out != NULL, NULL);
644 res = cellref_a1_get (out, ss, in, pos);
645 if (res != NULL)
646 return res;
647 return cellref_r1c1_get (out, ss, in, pos);
650 /****************************************************************************/
652 static char const *
653 cell_coord_name2 (int col, int row, gboolean r1c1)
655 static GString *buffer = NULL;
656 if (buffer)
657 g_string_truncate (buffer, 0);
658 else
659 buffer = g_string_new (NULL);
661 if (r1c1) {
662 r1c1_add_index (buffer, 'R', row, FALSE);
663 r1c1_add_index (buffer, 'C', col, FALSE);
664 } else {
665 col_name_internal (buffer, col);
666 row_name_internal (buffer, row);
669 return buffer->str;
673 * cell_coord_name: (skip)
674 * @col: column number
675 * @row: row number
677 * Returns: (transfer none): a string representation of the cell at (@col,@row)
679 char const *
680 cell_coord_name (int col, int row)
682 return cell_coord_name2 (col, row, FALSE);
686 * cellpos_as_string: (skip)
687 * @pos: A #GnmCellPos
689 * Returns: (transfer none): a string representation of the cell at @pos
691 char const *
692 cellpos_as_string (GnmCellPos const *pos)
694 g_return_val_if_fail (pos != NULL, "ERROR");
696 return cell_coord_name (pos->col, pos->row);
699 char const *
700 parsepos_as_string (GnmParsePos const *pp)
702 g_return_val_if_fail (pp != NULL, "ERROR");
704 return cell_coord_name2 (pp->eval.col,
705 pp->eval.row,
706 pp->sheet && pp->sheet->convs->r1c1_addresses);
710 * cell_name:
711 * @cell: #GnmCell
713 * Returns: (transfer none): the name of @cell, like "B11"
715 char const *
716 cell_name (GnmCell const *cell)
718 g_return_val_if_fail (cell != NULL, "ERROR");
720 return cell_coord_name2 (cell->pos.col,
721 cell->pos.row,
722 cell->base.sheet->convs->r1c1_addresses);
726 * cellpos_parse: (skip)
727 * @cell_str: a string representation of a cell name.
728 * @ss: #GnmSheetSize
729 * @res: result
730 * @strict: if this is %TRUE, then parsing stops at possible errors,
731 * otherwise an attempt is made to return cell names with
732 * trailing garbage.
734 * Returns: (transfer none): pointer to following char on success, %NULL on
735 * failure. (In the strict case, that would be a pointer to the \0 or %NULL.)
737 char const *
738 cellpos_parse (char const *cell_str, GnmSheetSize const *ss,
739 GnmCellPos *res, gboolean strict)
741 unsigned char dummy_relative;
743 cell_str = col_parse (cell_str, ss, &res->col, &dummy_relative);
744 if (!cell_str)
745 return NULL;
747 cell_str = row_parse (cell_str, ss, &res->row, &dummy_relative);
748 if (!cell_str)
749 return NULL;
751 if (*cell_str != 0 && strict)
752 return NULL;
754 return cell_str;
758 * gnm_expr_char_start_p: (skip)
759 * @c: string
761 * Can the supplied string be an expression ? It does not guarantee that it is,
762 * however, it is possible. If it is possible it strips off any header
763 * characters that are not relevant.
765 * NOTE : things like -1,234 will match
767 char const *
768 gnm_expr_char_start_p (char const * c)
770 char c0;
771 int N = 1;
773 if (NULL == c)
774 return NULL;
776 c0 = *c;
778 if (c0 == '=' || c0 == '@' || c0 == '+' || c0 == '-')
779 while (c[N] == ' ')
780 N++;
782 if (c0 == '=' || c0 == '@' || (c0 == '+' && c[1] == 0))
783 return c + N;
785 if ((c0 == '-' || c0 == '+') && c0 != c[1]) {
786 char *end;
789 * Ok, we have a string that
790 * 1. starts with a sign
791 * 2. does not start with the sign repeated (think --------)
792 * 3. is more than one character
794 * Now we check whether we have a number. We don't want
795 * numbers to be treated as formulae. FIXME: this really
796 * just checks for C-syntax numbers.
798 (void) gnm_strto (c, &end);
799 if (errno || *end != 0 || end == c)
800 return (c0 == '+') ? c + N : c;
801 /* Otherwise, it's a number. */
803 return NULL;
807 * parse_text_value_or_expr:
808 * @pos: If the string looks like an expression parse it at this location.
809 * @text: The text to be parsed.
810 * @val: (out): Returns a GnmValue* if the text was a value, otherwise NULL.
811 * @texpr: (out): Returns a GnmExprTop* if the text was an expression, otherwise NULL.
813 * Utility routine to parse a string and convert it into an expression or value.
815 * If there is a parse failure for an expression an error GnmValue with
816 * the syntax error is returned in @val.
818 void
819 parse_text_value_or_expr (GnmParsePos const *pos, char const *text,
820 GnmValue **val, GnmExprTop const **texpr)
822 char const *expr_start;
823 GODateConventions const *date_conv;
824 GOFormat const *cur_fmt;
825 GOFormat const *cell_fmt;
826 GnmStyle const *cell_style;
828 *texpr = NULL;
829 *val = NULL;
831 /* Determine context information. */
832 date_conv =
833 pos->sheet
834 ? sheet_date_conv (pos->sheet)
835 : (pos->wb
836 ? workbook_date_conv (pos->wb)
837 : NULL);
838 cell_style = pos->sheet
839 ? sheet_style_get (pos->sheet, pos->eval.col, pos->eval.row)
840 : NULL;
841 cur_fmt = cell_fmt = cell_style ? gnm_style_get_format (cell_style) : NULL;
842 if (cell_fmt && go_format_is_general (cell_fmt)) {
843 GnmCell const *cell = pos->sheet
844 ? sheet_cell_get (pos->sheet, pos->eval.col, pos->eval.row)
845 : NULL;
846 if (cell && cell->value && VALUE_FMT (cell->value))
847 cur_fmt = VALUE_FMT (cell->value);
850 /* Does it match any formats? */
851 *val = format_match (text, cur_fmt, date_conv);
852 if (*val != NULL) {
853 GOFormat const *val_fmt = VALUE_FMT (*val);
854 /* Avoid value formats we don't need. */
855 if (val_fmt && go_format_eq (cell_fmt, val_fmt))
856 value_set_fmt (*val, NULL);
857 return;
860 /* If it does not match known formats, see if it is an expression */
861 expr_start = gnm_expr_char_start_p (text);
862 if (NULL != expr_start && *expr_start) {
863 *texpr = gnm_expr_parse_str (expr_start, pos,
864 GNM_EXPR_PARSE_DEFAULT, NULL, NULL);
865 if (*texpr != NULL)
866 return;
869 /* Fall back on string */
870 *val = value_new_string (text);
873 GnmParseError *
874 parse_error_init (GnmParseError *pe)
876 pe->err = NULL;
877 pe->begin_char = 0;
878 pe->end_char = 0;
880 return pe;
883 void
884 parse_error_free (GnmParseError *pe)
886 if (pe->err != NULL) {
887 g_error_free (pe->err);
888 pe->err = NULL;
892 static GnmParseError *
893 gnm_parse_error_copy (GnmParseError *pe)
895 GnmParseError *res = g_new (GnmParseError, 1);
896 res->begin_char = pe->begin_char;
897 res->end_char = pe->end_char;
898 res->err = (pe->err)? g_error_copy (pe->err): NULL;
899 return res;
902 GType
903 gnm_parse_error_get_type (void)
905 static GType t = 0;
907 if (t == 0) {
908 t = g_boxed_type_register_static ("GnmParseError",
909 (GBoxedCopyFunc)gnm_parse_error_copy,
910 (GBoxedFreeFunc)parse_error_free);
912 return t;
915 /***************************************************************************/
917 static char const *
918 check_quoted (char const *start, int *num_escapes)
920 char const *str = start;
921 if (*str == '\'' || *str == '\"') {
922 char const quote = *str++;
923 *num_escapes = 0;
924 for (; *str && *str != quote; str = g_utf8_next_char (str))
925 if (*str == '\\' && str[1]) {
926 str++;
927 (*num_escapes)++;
929 if (*str)
930 return str+1;
931 } else
932 *num_escapes = -1;
933 return start;
936 static void
937 unquote (char *dst, char const *src, int n)
939 while (n-- > 0)
940 if (*src == '\\' && src[1]) {
941 int l = g_utf8_skip [*(guchar *)(++src)];
942 strncpy (dst, src, l);
943 dst += l;
944 src += l;
945 n -= l;
946 } else
947 *dst++ = *src++;
948 *dst = 0;
952 * wbref_parse:
953 * @convs: #GnmConventions const
954 * @start:
955 * @wb:
957 * Returns: %NULL if there is a valid workbook name but it is unknown.
958 * If the string is a valid workbook known name it returns a pointer
959 * the end of the name.
960 * Otherwise returns @start and does not modify @wb.
962 static char const *
963 wbref_parse (GnmConventions const *convs,
964 char const *start, Workbook **wb, Workbook *ref_wb)
966 /* Is this an external reference ? */
967 if (*start == '[') {
968 Workbook *tmp_wb;
970 int num_escapes;
971 char const *end = check_quoted (start+1, &num_escapes);
972 char *name;
974 if (end == start+1) {
975 end = strchr (start, ']');
976 if (end == NULL)
977 return start;
979 if (*end != ']')
980 return start;
982 if (num_escapes < 0)
983 name = g_strndup (start + 1, end - start - 1);
984 else {
985 name = g_malloc (1 + end - start - 2);
986 unquote (name, start+2, end-start-2);
989 tmp_wb = (*convs->input.external_wb) (convs, ref_wb, name);
990 g_free (name);
991 if (tmp_wb == NULL)
992 return NULL;
994 *wb = tmp_wb;
995 return end + 1;
998 return start;
1002 * sheetref_parse: (skip)
1003 * @convs: #GnmConventions
1004 * @start:
1005 * @sheet: (out)
1006 * @wb: A #Workbook
1007 * @allow_3d:
1009 * Returns: (transfer none): %NULL if there is a valid sheet name but it
1010 * is unknown. If the string is a valid sheet name it returns a pointer
1011 * the end of the name. Otherwise returns @start and does not
1012 * modify @sheet.
1014 static char const *
1015 sheetref_parse (GnmConventions const *convs,
1016 char const *start, Sheet **sheet, Workbook const *wb,
1017 gboolean allow_3d)
1019 GString *sheet_name;
1020 char const *end;
1022 *sheet = NULL;
1023 if (*start == '\'' || *start == '"') {
1024 sheet_name = g_string_new (NULL);
1025 end = go_strunescape (sheet_name, start);
1026 if (end == NULL) {
1027 g_string_free (sheet_name, TRUE);
1028 return start;
1030 } else {
1031 gboolean only_digits = TRUE;
1032 end = start;
1035 * Valid: Normal!a1
1036 * Valid: x.y!a1
1037 * Invalid: .y!a1
1039 * Some names starting with digits are actually valid, but
1040 * unparse quoted. Things are quite tricky: most sheet names
1041 * starting with a digit are ok, but not those starting with
1042 * "[0-9]*\." or "[0-9]+[eE]".
1044 * Valid: 42!a1
1045 * Valid: 4x!a1
1046 * Invalid: 1.!a1
1047 * Invalid: 1e!a1
1050 while (1) {
1051 gunichar uc = g_utf8_get_char (end);
1052 if (g_unichar_isalpha (uc) || uc == '_') {
1053 if (only_digits && end != start &&
1054 (uc == 'e' || uc == 'E')) {
1055 end = start;
1056 break;
1058 only_digits = FALSE;
1059 end = g_utf8_next_char (end);
1060 } else if (g_unichar_isdigit (uc)) {
1061 end = g_utf8_next_char (end);
1062 } else if (uc == '.') {
1063 /* Valid, except after only digits. */
1064 if (only_digits) {
1065 end = start;
1066 break;
1068 end++;
1069 } else
1070 break;
1073 if (*end != '!' && (!allow_3d || *end != ':'))
1074 return start;
1076 sheet_name = g_string_new_len (start, end - start);
1079 *sheet = workbook_sheet_by_name (wb, sheet_name->str);
1080 if (*sheet == NULL)
1081 end = start;
1083 g_string_free (sheet_name, TRUE);
1084 return end;
1087 static char const *
1088 r1c1_rangeref_parse (GnmRangeRef *res, char const *ptr, GnmParsePos const *pp)
1090 char const *tmp;
1091 GnmSheetSize const *a_ss, *b_ss;
1092 Sheet const *a_sheet, *b_sheet;
1094 a_sheet = eval_sheet (res->a.sheet, pp->sheet);
1095 b_sheet = eval_sheet (res->b.sheet, a_sheet);
1097 a_ss = gnm_sheet_get_size2 (a_sheet, pp->wb);
1098 b_ss = gnm_sheet_get_size2 (b_sheet, pp->wb);
1100 if (*ptr == 'R' || *ptr == 'r') {
1101 ptr = r1c1_get_index (ptr, a_ss,
1102 &res->a.row, &res->a.row_relative,
1103 FALSE);
1104 if (!ptr)
1105 return NULL;
1106 if (*ptr != 'C' && *ptr != 'c') {
1107 if (g_ascii_isalpha (*ptr))
1108 return NULL;
1109 /* full row R# */
1110 res->a.col_relative = FALSE;
1111 res->a.col = 0;
1112 res->b = res->a;
1113 res->b.col = a_ss->max_cols - 1;
1114 if (ptr[0] != ':' || (ptr[1] != 'R' && ptr[1] != 'r'))
1115 return ptr;
1116 tmp = r1c1_get_index (ptr+1, a_ss,
1117 &res->b.row, &res->b.row_relative,
1118 FALSE);
1119 if (!tmp)
1120 return ptr; /* fallback to just the initial R */
1121 return tmp;
1122 } else {
1123 ptr = r1c1_get_index (ptr, a_ss,
1124 &res->a.col, &res->a.col_relative,
1125 TRUE);
1126 if (!ptr)
1127 return NULL;
1130 res->b = res->a;
1131 if (ptr[0] != ':' || (ptr[1] != 'R' && ptr[1] != 'r') ||
1132 NULL == (tmp = r1c1_get_index (ptr+1, b_ss,
1133 &res->b.row, &res->b.row_relative, FALSE)) ||
1134 (*tmp != 'C' && *tmp != 'c') ||
1135 NULL == (tmp = r1c1_get_index (tmp, b_ss,
1136 &res->b.col, &res->b.col_relative, FALSE)))
1137 return ptr;
1138 return tmp;
1139 } else if (*ptr == 'C' || *ptr == 'c') {
1140 if (NULL == (ptr = r1c1_get_index (ptr, a_ss,
1141 &res->a.col, &res->a.col_relative, TRUE)))
1142 return NULL;
1143 if (g_ascii_isalpha (*ptr))
1144 return NULL;
1145 /* full col C[#] */
1146 res->a.row_relative = FALSE;
1147 res->a.row = 0;
1148 res->b = res->a;
1149 res->b.row = b_ss->max_rows - 1;
1150 if (ptr[0] != ':' || (ptr[1] != 'C' && ptr[1] != 'c'))
1151 return ptr;
1152 tmp = r1c1_get_index (ptr, b_ss,
1153 &res->b.col, &res->b.col_relative,
1154 TRUE);
1155 if (!tmp)
1156 return ptr; /* fallback to just the initial C */
1157 return tmp;
1160 return NULL;
1164 * rangeref_parse: (skip)
1165 * @res: (out): #GnmRangeRef
1166 * @start: the start of the string to parse
1167 * @pp: the location to parse relative to
1168 * @convs: #GnmConventions
1170 * Returns: (transfer none): a pointer to the first invalid character.
1171 * If the result != @start then @res is valid.
1173 char const *
1174 rangeref_parse (GnmRangeRef *res, char const *start, GnmParsePos const *pp,
1175 GnmConventions const *convs)
1177 char const *ptr = start, *start_sheet, *start_wb, *tmp1, *tmp2;
1178 Workbook *wb;
1179 Workbook *ref_wb;
1180 Sheet *a_sheet, *b_sheet;
1181 GnmSheetSize const *a_ss, *b_ss;
1183 g_return_val_if_fail (start != NULL, start);
1184 g_return_val_if_fail (pp != NULL, start);
1186 wb = pp->wb;
1187 ref_wb = wb ? wb : pp->sheet->workbook;
1188 start_wb = start;
1189 start_sheet = wbref_parse (convs, start, &wb, ref_wb);
1190 if (start_sheet == NULL)
1191 return start; /* TODO error unknown workbook */
1192 ptr = sheetref_parse (convs, start_sheet, &res->a.sheet, wb, TRUE);
1193 if (ptr == NULL)
1194 return start; /* TODO error unknown sheet */
1195 if (ptr != start_sheet) {
1196 const char *ref;
1198 if (*ptr == ':') { /* 3d ref */
1199 ptr = sheetref_parse (convs, ptr+1, &res->b.sheet, wb, FALSE);
1200 if (ptr == NULL)
1201 return start; /* TODO error unknown sheet */
1202 } else
1203 res->b.sheet = NULL;
1205 if (*ptr++ != '!')
1206 return start; /* TODO syntax error */
1208 ref = value_error_name (GNM_ERROR_REF, FALSE);
1209 if (strncmp (ptr, ref, strlen (ref)) == 0) {
1210 res->a.sheet = invalid_sheet;
1211 res->a.col = res->a.row = 0;
1212 res->a.col_relative = res->a.row_relative = FALSE;
1213 res->b.sheet = res->a.sheet;
1214 ptr += strlen (ref);
1215 return ptr;
1217 } else {
1218 if (start_sheet != start_wb)
1219 return start; /* Workbook, but no sheet. */
1220 res->b.sheet = NULL;
1223 if (convs->r1c1_addresses) { /* R1C1 handler */
1224 const char *tmp1 = r1c1_rangeref_parse (res, ptr, pp);
1225 return (tmp1 != NULL) ? tmp1 : start;
1228 a_sheet = eval_sheet (res->a.sheet, pp->sheet);
1229 b_sheet = eval_sheet (res->b.sheet, a_sheet);
1231 a_ss = gnm_sheet_get_size2 (a_sheet, pp->wb);
1232 b_ss = gnm_sheet_get_size2 (b_sheet, pp->wb);
1234 tmp1 = col_parse (ptr, a_ss, &res->a.col, &res->a.col_relative);
1235 if (tmp1 == NULL) { /* check for row only ref 2:3 */
1236 tmp1 = row_parse (ptr, a_ss,
1237 &res->a.row, &res->a.row_relative);
1238 if (!tmp1 || *tmp1++ != ':') /* row only requires : even for singleton */
1239 return start;
1240 tmp2 = row_parse (tmp1, b_ss,
1241 &res->b.row, &res->b.row_relative);
1242 if (!tmp2)
1243 return start;
1244 res->a.col_relative = res->b.col_relative = FALSE;
1245 res->a.col = 0;
1246 res->b.col = b_ss->max_cols - 1;
1247 if (res->a.row_relative)
1248 res->a.row -= pp->eval.row;
1249 if (res->b.row_relative)
1250 res->b.row -= pp->eval.row;
1251 return tmp2;
1254 tmp2 = row_parse (tmp1, a_ss, &res->a.row, &res->a.row_relative);
1255 if (tmp2 == NULL) { /* check for col only ref B:C or R1C1 style */
1256 if (*tmp1++ != ':') /* col only requires : even for singleton */
1257 return start;
1258 tmp2 = col_parse (tmp1, a_ss,
1259 &res->b.col, &res->b.col_relative);
1260 if (!tmp2)
1261 return start;
1262 res->a.row_relative = res->b.row_relative = FALSE;
1263 res->a.row = 0;
1264 res->b.row = b_ss->max_rows - 1;
1265 if (res->a.col_relative)
1266 res->a.col -= pp->eval.col;
1267 if (res->b.col_relative)
1268 res->b.col -= pp->eval.col;
1269 return tmp2;
1272 if (res->a.col_relative)
1273 res->a.col -= pp->eval.col;
1274 if (res->a.row_relative)
1275 res->a.row -= pp->eval.row;
1277 ptr = tmp2;
1278 if (*ptr != ':')
1279 goto singleton;
1281 tmp1 = col_parse (ptr+1, b_ss, &res->b.col, &res->b.col_relative);
1282 if (!tmp1)
1283 goto singleton; /* strange, but valid singleton */
1284 tmp2 = row_parse (tmp1, b_ss, &res->b.row, &res->b.row_relative);
1285 if (!tmp2)
1286 goto singleton; /* strange, but valid singleton */
1288 if (res->b.col_relative)
1289 res->b.col -= pp->eval.col;
1290 if (res->b.row_relative)
1291 res->b.row -= pp->eval.row;
1292 return tmp2;
1294 singleton:
1295 res->b.col = res->a.col;
1296 res->b.row = res->a.row;
1297 res->b.col_relative = res->a.col_relative;
1298 res->b.row_relative = res->a.row_relative;
1299 return ptr;
1302 /* ------------------------------------------------------------------------- */
1304 static void
1305 std_expr_func_handler (GnmConventionsOut *out, GnmExprFunction const *func)
1307 char const *name = gnm_func_get_name (func->func,
1308 out->convs->localized_function_names);
1309 GString *target = out->accum;
1311 g_string_append (target, name);
1312 /* FIXME: possibly a space here. */
1313 gnm_expr_list_as_string (func->argc, func->argv, out);
1316 static void
1317 std_expr_name_handler (GnmConventionsOut *out, GnmExprName const *name)
1319 GnmNamedExpr const *thename = name->name;
1320 GString *target = out->accum;
1322 if (!expr_name_is_active (thename)) {
1323 g_string_append (target,
1324 value_error_name (GNM_ERROR_REF,
1325 out->convs->output.translated));
1326 return;
1329 if (name->optional_scope != NULL) {
1330 Workbook *out_wb = out->pp->wb
1331 ? out->pp->wb
1332 : out->pp->sheet->workbook;
1333 if (name->optional_scope->workbook != out_wb) {
1334 char *rel_uri = wb_rel_uri (name->optional_scope->workbook, out_wb);
1335 g_string_append_c (target, '[');
1336 g_string_append (target, rel_uri);
1337 g_string_append_c (target, ']');
1338 g_free (rel_uri);
1339 } else {
1340 g_string_append (target, name->optional_scope->name_quoted);
1341 g_string_append_unichar (target, out->convs->sheet_name_sep);
1343 } else if (out->pp->sheet != NULL &&
1344 thename->pos.sheet != NULL &&
1345 thename->pos.sheet != out->pp->sheet) {
1346 g_string_append (target, thename->pos.sheet->name_quoted);
1347 g_string_append_unichar (target, out->convs->sheet_name_sep);
1348 } else if (out->pp->sheet &&
1349 thename->pos.sheet == NULL &&
1350 expr_name_lookup (out->pp, expr_name_name (thename)) != thename) {
1351 /* Special syntax for global names shadowed by sheet names. */
1352 g_string_append (target, "[]");
1355 g_string_append (target, expr_name_name (thename));
1358 static void
1359 std_output_string (GnmConventionsOut *out, GOString const *str)
1361 go_strescape (out->accum, str->str);
1364 /* ------------------------------------------------------------------------- */
1366 static GString *
1367 std_sheet_name_quote (GnmConventions const *convs,
1368 char const *str)
1370 gunichar uc = g_utf8_get_char (str);
1371 GString *res = g_string_sized_new (20);
1372 char const *p;
1373 int nletters;
1374 int ndigits;
1376 if (g_ascii_isalpha (uc)) {
1377 nletters = 1;
1378 ndigits = 0;
1379 p = str + 1;
1380 } else if (g_unichar_isalpha (uc) || uc == '_') {
1381 nletters = -1;
1382 ndigits = -1;
1383 p = g_utf8_next_char (str);
1384 } else
1385 goto quoted;
1387 /* FIXME: What about '?' and '\\'. I cannot enter those. */
1389 for (; *p; p = g_utf8_next_char (p)) {
1390 uc = g_utf8_get_char (p);
1392 if (g_ascii_isalpha (uc)) {
1393 if (ndigits == 0)
1394 nletters++;
1395 } else if (g_ascii_isdigit (uc)) {
1396 if (ndigits >= 0)
1397 ndigits++;
1398 } else if (uc == '.' || uc == '_' || g_unichar_isalpha (uc))
1399 nletters = ndigits = -1;
1400 else
1401 goto quoted;
1404 if (ndigits > 0) {
1405 static const GnmSheetSize max_size = {
1406 GNM_MAX_COLS, GNM_MAX_ROWS
1409 * Excel also quotes things that look like cell references.
1410 * Precisely, check for a match against
1411 * ([A-Za-z]+)0*([1-9][0-9]*)
1412 * where $1 is a valid column name and $2 is a valid row
1413 * number. (The 0* is an Excel bug.)
1416 int col, row;
1417 unsigned char col_relative, row_relative;
1418 if (!col_parse (str, &max_size, &col, &col_relative))
1419 goto unquoted;
1421 p = str + nletters;
1422 while (*p == '0')
1423 p++, ndigits--;
1424 if (!row_parse (p, &max_size, &row, &row_relative))
1425 goto unquoted;
1427 goto quoted;
1430 unquoted:
1431 g_string_append (res, str);
1432 return res;
1434 quoted:
1435 g_string_append_c (res, '\'');
1436 /* This is UTF-8 safe. */
1437 for (; *str; str++) {
1438 gchar c = *str;
1439 if (c == '\'' || c == '\\')
1440 g_string_append_c (res, '\\');
1441 g_string_append_c (res, c);
1443 g_string_append_c (res, '\'');
1445 return res;
1448 static char const *
1449 std_name_parser (char const *str,
1450 G_GNUC_UNUSED GnmConventions const *convs)
1452 gunichar uc = g_utf8_get_char (str);
1454 if (!g_unichar_isalpha (uc) && uc != '_' && uc != '\\')
1455 return NULL;
1457 do {
1458 str = g_utf8_next_char (str);
1459 uc = g_utf8_get_char (str);
1460 } while (g_unichar_isalnum (uc) ||
1461 uc == '_' ||
1462 uc == '?' ||
1463 uc == '\\' ||
1464 uc == '.');
1466 return str;
1469 static GnmExpr const *
1470 std_func_map (GnmConventions const *convs, Workbook *scope,
1471 char const *name, GnmExprList *args)
1473 GnmFunc *f = convs->localized_function_names
1474 ? gnm_func_lookup_localized (name, scope)
1475 : gnm_func_lookup (name, scope);
1477 if (!f) {
1478 f = convs->localized_function_names
1479 ? gnm_func_add_placeholder_localized (NULL, name)
1480 : gnm_func_add_placeholder_localized (name, NULL);
1483 return gnm_expr_new_funcall (f, args);
1486 static Workbook *
1487 std_external_wb (G_GNUC_UNUSED GnmConventions const *convs,
1488 Workbook *ref_wb,
1489 const char *wb_name)
1491 const char *ref_uri = ref_wb ? go_doc_get_uri ((GODoc *)ref_wb) : NULL;
1492 return gnm_app_workbook_get_by_name (wb_name, ref_uri);
1495 static char const *
1496 std_string_parser (char const *in, GString *target,
1497 G_GNUC_UNUSED GnmConventions const *convs)
1499 return go_strunescape (target, in);
1503 * gnm_conventions_new_full:
1504 * @size:
1506 * Construct a GnmConventions of @size.
1508 * Returns: (transfer full): A #GnmConventions with default values.
1510 GnmConventions *
1511 gnm_conventions_new_full (unsigned size)
1513 GnmConventions *convs;
1515 g_return_val_if_fail (size >= sizeof (GnmConventions), NULL);
1517 convs = g_malloc0 (size);
1518 convs->ref_count = 1;
1520 convs->r1c1_addresses = FALSE;
1521 convs->localized_function_names = FALSE;
1523 convs->sheet_name_sep = '!';
1524 convs->intersection_char = ' ';
1525 convs->exp_is_left_associative = FALSE;
1526 convs->input.range_ref = rangeref_parse;
1527 convs->input.string = std_string_parser;
1528 convs->input.name = std_name_parser;
1529 convs->input.name_validate = expr_name_validate;
1530 convs->input.func = std_func_map;
1531 convs->input.external_wb = std_external_wb;
1533 convs->output.decimal_digits = -1;
1534 convs->output.translated = TRUE;
1535 convs->output.string = std_output_string;
1536 convs->output.name = std_expr_name_handler;
1537 convs->output.func = std_expr_func_handler;
1538 convs->output.cell_ref = cellref_as_string;
1539 convs->output.range_ref = rangeref_as_string;
1540 convs->output.boolean = NULL;
1541 convs->output.quote_sheet_name = std_sheet_name_quote;
1543 return convs;
1547 * gnm_conventions_new:
1549 * A convenience wrapper around gnm_conventions_new_full
1550 * that constructs a GnmConventions of std size.
1552 * Returns: (transfer full): A #GnmConventions with default values.
1554 GnmConventions *
1555 gnm_conventions_new (void)
1557 return gnm_conventions_new_full (sizeof (GnmConventions));
1561 * gnm_conventions_unref: (skip)
1562 * @c: (transfer full): #GnmConventions
1564 * Release a reference to a #GnmConvention
1566 void
1567 gnm_conventions_unref (GnmConventions *c)
1569 if (c == NULL)
1570 return;
1572 g_return_if_fail (c->ref_count > 0);
1574 c->ref_count--;
1575 if (c->ref_count > 0)
1576 return;
1578 g_free (c);
1582 * gnm_conventions_ref: (skip)
1583 * @c: (transfer none) (nullable): #GnmConventions
1585 * Returns: (transfer full) (nullable): a new reference to @c
1587 GnmConventions *
1588 gnm_conventions_ref (GnmConventions const *c)
1590 GnmConventions *uc = (GnmConventions *)c;
1591 if (uc)
1592 uc->ref_count++;
1593 return uc;
1596 GType
1597 gnm_conventions_get_type (void)
1599 static GType t = 0;
1601 if (t == 0) {
1602 t = g_boxed_type_register_static ("GnmConventions",
1603 (GBoxedCopyFunc)gnm_conventions_ref,
1604 (GBoxedFreeFunc)gnm_conventions_unref);
1606 return t;
1609 /* ------------------------------------------------------------------------- */
1611 GnmConventions const *gnm_conventions_default;
1612 GnmConventions const *gnm_conventions_xls_r1c1;
1614 void
1615 parse_util_init (void)
1617 GnmConventions *convs;
1619 convs = gnm_conventions_new ();
1620 convs->range_sep_colon = TRUE;
1621 convs->r1c1_addresses = FALSE;
1622 /* Not ready for general use yet. */
1623 convs->localized_function_names = g_getenv ("GNM_LOCAL_FUNCS") != NULL;
1624 gnm_conventions_default = convs;
1626 convs = gnm_conventions_new ();
1627 convs->range_sep_colon = TRUE;
1628 convs->r1c1_addresses = TRUE;
1629 convs->localized_function_names = gnm_conventions_default->localized_function_names;
1630 gnm_conventions_xls_r1c1 = convs;
1633 void
1634 parse_util_shutdown (void)
1636 gnm_conventions_unref ((GnmConventions *)gnm_conventions_default);
1637 gnm_conventions_default = NULL;
1638 gnm_conventions_unref ((GnmConventions *)gnm_conventions_xls_r1c1);
1639 gnm_conventions_xls_r1c1 = NULL;
1642 /* ------------------------------------------------------------------------- */
1644 * gnm_expr_conv_quote:
1645 * @convs: #GnmConventions
1646 * @str: string to quote
1648 * Returns: (transfer full): A quoted string according to @convs. If no
1649 * quoting is necessary, a literal copy of @str will be returned.
1651 GString *
1652 gnm_expr_conv_quote (GnmConventions const *convs,
1653 char const *str)
1655 g_return_val_if_fail (convs != NULL, NULL);
1656 g_return_val_if_fail (convs->output.quote_sheet_name != NULL, NULL);
1657 g_return_val_if_fail (str != NULL, NULL);
1658 g_return_val_if_fail (str[0] != 0, NULL);
1660 return convs->output.quote_sheet_name (convs, str);