Update Spanish translation
[gnumeric.git] / plugins / oleo / oleo.c
blob2999756c373d531b755a9c6130c84e6406d2c12b
1 /*
2 * GNU Oleo input filter for Gnumeric
4 * Author:
5 * Robert Brady <rwb197@ecs.soton.ac.uk>
7 * partially based on the Lotus-123 code,
8 * partially based on actual Oleo code.
9 */
10 #include <gnumeric-config.h>
11 #include <glib/gi18n-lib.h>
12 #include <gnumeric.h>
13 #include "oleo.h"
15 #include <workbook.h>
16 #include <sheet.h>
17 #include <cell.h>
18 #include <value.h>
19 #include <parse-util.h>
20 #include <expr.h>
21 #include <sheet-style.h>
22 #include <mstyle.h>
23 #include <ranges.h>
24 #include <number-match.h>
25 #include <func.h>
27 #include <gsf/gsf-input-textline.h>
29 #include <string.h>
30 #include <stdlib.h>
32 #define OLEO_DEBUG 0
35 typedef struct {
36 GnmConventions *convs;
37 GnmParsePos pp;
39 GsfInputTextline *textline;
40 GIConv converter;
41 } OleoReader;
43 static void
44 append_zeros (GString *s, int n)
46 if (n > 0) {
47 size_t oldlen = s->len;
48 g_string_set_size (s, oldlen + n);
49 memset (s->str+oldlen, '0', n);
53 /* adapted from Oleo */
54 static long
55 astol (char **ptr)
57 char *end;
58 long res;
60 res = strtol (*ptr, &end, 10);
61 *ptr = end;
63 return res;
67 static void
68 oleo_set_style (OleoReader *state, GnmStyle *style)
70 /* sheet_style_set_range absorbs our reference */
71 gnm_style_ref (style);
72 sheet_style_set_pos (state->pp.sheet,
73 state->pp.eval.col, state->pp.eval.row, style);
76 static GnmExprTop const *
77 oleo_parse_formula (OleoReader *state, char const *expr_str)
79 GnmParseError error;
80 GnmExprTop const *texpr = gnm_expr_parse_str (expr_str,
81 &state->pp, GNM_EXPR_PARSE_DEFAULT,
82 state->convs, parse_error_init (&error));
84 if (error.err != NULL) {
85 g_warning ("%s \"%s\" at %s!%s.", error.err->message, expr_str,
86 state->pp.sheet->name_unquoted,
87 cell_coord_name (state->pp.eval.col, state->pp.eval.row));
89 parse_error_free (&error);
91 return texpr;
94 static void
95 oleo_parse_cell (OleoReader *state, guint8 *str, GnmStyle *style)
97 GnmCell *cell;
98 GnmExprTop const *texpr = NULL;
99 char *ptr = str + 1, *cval = NULL, *formula = NULL;
101 while (*ptr) {
102 int quotes = 0;
103 if (*ptr != ';') {
104 #if OLEO_DEBUG > 0
105 g_warning ("ptr: %s.", ptr);
106 #endif
107 break;
109 *ptr++ = '\0';
110 switch (*ptr++) {
111 case 'c' : state->pp.eval.col = astol (&ptr) - 1; break;
112 case 'r' : state->pp.eval.row = astol (&ptr) - 1; break;
113 case 'K' :
114 cval = ptr;
115 quotes = 0;
116 while (*ptr && (*ptr != ';' || quotes > 0))
117 if (*ptr++ == '"')
118 quotes = !quotes;
119 break;
121 case 'E' :
122 formula = ptr;
123 while (*ptr && *ptr != ';')
124 ptr++;
125 break;
127 default:
128 #if OLEO_DEBUG > 0
129 g_warning ("oleo: Don't know how to deal with C; '%c'.",
130 *ptr);
131 #endif
132 ptr = (char *)""; /* I wish C had multilevel break */
133 break;
136 if (!*ptr)
137 break;
140 cell = sheet_cell_fetch (state->pp.sheet,
141 state->pp.eval.col, state->pp.eval.row);
143 if (formula != NULL)
144 texpr = oleo_parse_formula (state, formula);
146 if (cval != NULL) {
147 GnmValue *val = format_match_simple (cval);
149 if (val == NULL) {
150 char *last = cval + strlen (cval) - 1;
151 if (*cval == '"' && *last == '"') {
152 *last = 0;
153 val = value_new_string (cval + 1);
154 } else
155 val = value_new_string (cval);
158 if (texpr != NULL)
159 gnm_cell_set_expr_and_value (cell, texpr, val, TRUE);
160 else
161 gnm_cell_set_value (cell, val);
163 if (style != NULL)
164 oleo_set_style (state, style);
166 } else {
167 #if OLEO_DEBUG > 0
168 g_warning ("oleo: cval is NULL.");
169 #endif
170 /* We can still store the expression, even if the value is missing */
171 if (texpr != NULL)
172 gnm_cell_set_expr (cell, texpr);
174 if (texpr)
175 gnm_expr_top_unref (texpr);
178 /* NOTE : We don't care too much about formatting as such, but we need to
179 * parse the command as it may update current row/column */
180 static void
181 oleo_parse_style (OleoReader *state, guint8 *str, GnmStyle **res)
183 char *ptr = str + 1;
184 GnmStyle *style = gnm_style_new_default ();
185 GString *fmt_string = g_string_new (NULL);
187 while (*ptr) {
188 char c = *ptr++;
190 switch (c) {
191 case 'c' : state->pp.eval.col = astol (&ptr) - 1; break;
192 case 'r' : state->pp.eval.row = astol (&ptr) - 1; break;
193 case 'F': case 'G':
194 c = *ptr++;
196 g_string_truncate (fmt_string, 0);
197 g_string_append_c (fmt_string, '0');
198 if (g_ascii_isdigit (*ptr))
199 append_zeros (fmt_string, astol (&ptr));
200 switch (c) {
201 case 'F':
202 break;
203 case '%':
204 g_string_append_c (fmt_string, '%');
205 break;
206 default: /* Unknown format type... */
207 g_string_truncate (fmt_string, 0);
209 break;
210 case 'L':
211 gnm_style_set_align_h (style, GNM_HALIGN_LEFT);
212 break;
213 case 'R':
214 gnm_style_set_align_h (style, GNM_HALIGN_RIGHT);
217 if (fmt_string->len)
218 gnm_style_set_format_text (style, fmt_string->str);
219 g_string_free (fmt_string, TRUE);
221 if (*res)
222 gnm_style_unref (*res);
223 *res = style;
226 static Sheet *
227 oleo_new_sheet (Workbook *wb, int idx)
229 char *sheet_name = g_strdup_printf (_("Sheet%d"), idx);
230 Sheet *sheet = sheet_new (wb, sheet_name, 256, 65536);
231 g_free (sheet_name);
232 workbook_sheet_attach (wb, sheet);
234 /* Ensure that things get rendered and spanned */
235 sheet_flag_recompute_spans (sheet);
236 return sheet;
239 static GnmConventions *
240 oleo_conventions_new (void)
242 GnmConventions *convs = gnm_conventions_new ();
244 convs->decimal_sep_dot = TRUE;
245 convs->intersection_char = 0;
246 convs->r1c1_addresses = TRUE;
248 return convs;
251 void
252 oleo_read (GOIOContext *io_context, Workbook *wb, GsfInput *input)
254 int sheetidx = 0;
255 GnmStyle *style = NULL;
256 guint8 *line;
257 OleoReader state;
259 state.convs = oleo_conventions_new ();
260 parse_pos_init (&state.pp,
261 wb, oleo_new_sheet (wb, ++sheetidx), 0, 0);
263 /* Does this need to come from the import dialog ? */
264 state.converter = g_iconv_open ("UTF-8", "ISO-8859-1");
265 state.textline = (GsfInputTextline *) gsf_input_textline_new (input);
267 while (NULL != (line = gsf_input_textline_ascii_gets (state.textline))) {
268 char *utf8line =
269 g_convert_with_iconv (line, -1, state.converter, NULL, NULL, NULL);
271 switch (utf8line[0]) {
272 case '#': /* Comment */
273 break;
275 case 'C': oleo_parse_cell (&state, utf8line, style);
276 break;
278 case 'F': oleo_parse_style (&state, utf8line, &style);
279 break;
281 default: /* unknown */
282 #if OLEO_DEBUG > 0
283 g_warning ("oleo: Don't know how to deal with %c.",
284 line[0]);
285 #endif
286 break;
289 g_free (utf8line);
292 if (style)
293 gnm_style_unref (style);
295 g_iconv_close (state.converter);
296 gnm_conventions_unref (state.convs);
297 g_object_unref (state.textline);