applix-read.c 42.6 KB
Newer Older
1
/* vim: set sw=8: */
2 3

/*
Jody Goldberg's avatar
Jody Goldberg committed
4
 * applix-read.c : Routines to read applix version 4 & 5 spreadsheets.
5
 *
6
 * Copyright (C) 2000-2002 Jody Goldberg (jody@gnome.org)
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
21 22
 * USA
 */
23

24 25 26 27
/*
 * I do not have much in the way of useful docs.
 * This is a guess based on some sample sheets with a few pointers from
 * 	http://www.vistasource.com/products/axware/fileformats/wptchc01.html
28 29
 */

30
#include <gnumeric-config.h>
31
#include <glib/gi18n.h>
32
#include <gnumeric.h>
33 34
#include "applix.h"

Jody Goldberg's avatar
Jody Goldberg committed
35 36
#include <application.h>
#include <expr.h>
37
#include <expr-name.h>
Jody Goldberg's avatar
Jody Goldberg committed
38 39
#include <value.h>
#include <sheet.h>
40
#include <sheet-view.h>
Jody Goldberg's avatar
Jody Goldberg committed
41 42 43 44 45 46 47 48 49 50
#include <number-match.h>
#include <cell.h>
#include <parse-util.h>
#include <sheet-style.h>
#include <style.h>
#include <style-border.h>
#include <style-color.h>
#include <selection.h>
#include <position.h>
#include <ranges.h>
51
#include <command-context.h>
Jody Goldberg's avatar
Jody Goldberg committed
52 53
#include <workbook-view.h>
#include <workbook.h>
54
#include <parse-util.h>
Jody Goldberg's avatar
Jody Goldberg committed
55

Stepan Kasal's avatar
Stepan Kasal committed
56 57
#include <goffice/app/io-context.h>
#include <goffice/app/error-info.h>
Jody Goldberg's avatar
Jody Goldberg committed
58
#include <gsf/gsf-input-textline.h>
59 60 61 62
#include <string.h>
#include <stdlib.h>

typedef struct {
Jody Goldberg's avatar
Jody Goldberg committed
63
	GsfInputTextline *input;
64 65 66 67
	ErrorInfo     *parse_error;
	WorkbookView  *wb_view;
	Workbook      *wb;
	GHashTable    *exprs, *styles;
68
	GPtrArray     *colors;
69 70
	GPtrArray     *attrs;
	GPtrArray     *font_names;
71

72
	unsigned char *buffer;
Jody Goldberg's avatar
Jody Goldberg committed
73 74
	size_t buffer_size;
	size_t line_len;
75
	int zoom;
76
	GSList *sheet_order;
77
	GSList *std_names, *real_names;
78 79

	GnmExprConventions *exprconv;
80 81
} ApplixReadState;

82 83 84 85 86 87 88 89
/* #define NO_DEBUG_APPLIX */
#ifndef NO_DEBUG_APPLIX
#define d(level, code)	do { if (debug_applix_read > level) { code } } while (0)
static int debug_applix_read = 0;
#else
#define d(level, code)
#endif

Jody Goldberg's avatar
Jody Goldberg committed
90 91
#define a_strncmp(buf, str) strncmp ((buf), str, sizeof (str) - 1)

92 93 94
/* The maximum numer of character potentially involved in a new line */
#define MAX_END_OF_LINE_SLOP	16

95 96
static int applix_parse_error (ApplixReadState *, char const *format, ...)
	G_GNUC_PRINTF (2, 3);
97

98
static int
99
applix_parse_error (ApplixReadState *state, char const *format, ...)
100
{
101 102 103 104
	va_list args;
	char *err;

	if (state->parse_error == NULL)
105
		state->parse_error = error_info_new_str (
106
			_("Parse error while reading Applix file."));
107 108 109 110 111 112 113 114

	va_start (args, format);
	err = g_strdup_vprintf (format, args);
	va_end (args);

	error_info_add_details (state->parse_error, error_info_new_str (err));
	g_free (err);

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
	return -1;
}

/**
 * applix_parse_value : Parse applix's optionally quoted values.
 *
 * @follow : A pointer to a char * that is adjusted to point 2 chars AFTER the
 *           end of the string.
 *
 * returns the strings and null terminates it.
 */
static char *
applix_parse_value (char *buf, char **follow)
{
	/* Is the value a quoted string */
	if (*buf == '"') {
		char *src = ++buf, *dest = src;
		while (*src && *src != '"') {
			if (*src == '\\')
				src++;
			*dest = *src++;
		}
137
		g_return_val_if_fail (*src == '"', NULL);
138
		*follow = src;
139 140
		**follow = '\0';
		*follow += 3;
141 142 143
	} else {
		*follow = strchr (buf, ' ');
		g_return_val_if_fail (*follow != NULL, NULL);
144 145
		**follow = '\0';
		*follow += 2;
146 147 148 149 150
	}

	return buf;
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
static char const *
applix_sheetref_parse (char const *start, Sheet **sheet, Workbook const *wb)
{
	char const *end, *begin;
	char *name;

	begin = end = (*start == '$') ? start + 1 : start;
	while (*end && g_ascii_isalnum (*end))
		end++;

	if (*end != ':') {
		*sheet = NULL;
		return start;
	}

	name = g_alloca (1 + end - begin);
	strncpy (name, begin, end-begin);
	name [end-begin] = '\0';
	*sheet = workbook_sheet_by_name (wb, name);
	return *sheet != NULL ? end : start;
}

173
static char const *
Jody Goldberg's avatar
Jody Goldberg committed
174 175
applix_rangeref_parse (GnmRangeRef *res, char const *start, GnmParsePos const *pp,
		       GnmExprConventions const *convention)
176 177 178 179 180 181 182 183 184
{
	char const *ptr = start, *tmp1, *tmp2;
	Workbook *wb = pp->wb;

	g_return_val_if_fail (start != NULL, start);
	g_return_val_if_fail (pp != NULL, start);

	/* TODO : Does not handle external references */

185 186 187 188 189
	ptr = applix_sheetref_parse (start, &res->a.sheet, wb);
	if (ptr == NULL)
		return start; /* TODO error unknown sheet */
	if (*ptr == ':') ptr++;
	tmp1 = col_parse (ptr, &res->a.col, &res->a.col_relative);
190
	if (!tmp1)
191 192
		return start;
	tmp2 = row_parse (tmp1, &res->a.row, &res->a.row_relative);
193
	if (!tmp2)
194 195 196 197 198 199 200 201 202
		return start;
	if (res->a.col_relative)
		res->a.col -= pp->eval.col;
	if (res->a.row_relative)
		res->a.row -= pp->eval.row;
	if (tmp2[0] != '.' || tmp2[1] != '.') {
		res->b = res->a;
		return tmp2;
	}
203

204
	start = tmp2;
205 206 207 208 209
	ptr = applix_sheetref_parse (start+2, &res->b.sheet, wb);
	if (ptr == NULL)
		return start; /* TODO error unknown sheet */
	if (*ptr == ':') ptr++;
	tmp1 = col_parse (ptr, &res->b.col, &res->b.col_relative);
210
	if (!tmp1)
211 212
		return start;
	tmp2 = row_parse (tmp1, &res->b.row, &res->b.row_relative);
213
	if (!tmp2)
214 215 216 217 218 219 220 221
		return start;
	if (res->b.col_relative)
		res->b.col -= pp->eval.col;
	if (res->b.row_relative)
		res->b.row -= pp->eval.row;
	return tmp2;
}

Jody Goldberg's avatar
Jody Goldberg committed
222 223
static unsigned char *
applix_get_line (ApplixReadState *state)
224
{
225
	unsigned char *ptr, *end, *buf;
Jody Goldberg's avatar
Jody Goldberg committed
226
	size_t len, skip = 0, offset = 0;
227

Jody Goldberg's avatar
Jody Goldberg committed
228 229
	while (NULL != (ptr = gsf_input_textline_ascii_gets (state->input))) {
		len = strlen (ptr);
230

Jody Goldberg's avatar
Jody Goldberg committed
231 232 233
		/* Clip at the state line length */
		if (len > state->line_len)
			len = state->line_len;
234

Jody Goldberg's avatar
Jody Goldberg committed
235 236 237 238
		if ((offset + len) > state->buffer_size) {
			state->buffer_size += state->line_len;
			state->buffer = g_realloc (state->buffer, state->buffer_size + 1);
		}
239 240 241 242 243 244 245 246 247 248 249 250

		end = ptr + len;
		ptr += skip;
		buf = state->buffer + offset;
		while (ptr < end) {
			if (*ptr == '^') {
				if (ptr [1] != '^') {
					if (ptr [1] == '\0' || ptr [2] == '\0') {
						applix_parse_error (state, _("Missing characters for character encoding"));
						*(buf++) = *(ptr++);
					} else if (ptr [1] < 'a' || ptr [1] > 'p' ||
						   ptr [2] < 'a' || ptr [2] > 'p') {
Jody Goldberg's avatar
Jody Goldberg committed
251
						applix_parse_error (state, _("Invalid characters for encoding '%c%c'"),
252 253 254 255 256 257 258 259 260 261 262 263 264
								    ptr[1], ptr[2]);
						*(buf++) = *(ptr++);
					} else {
						*(buf++) = ((ptr[1] - 'a') << 8) | (ptr[2] - 'a');
						ptr += 3;
					}
				} else /* an encoded carat */
					*(buf++) = '^', ptr += 2;
			} else
				*(buf++) = *(ptr++);
		}

		offset = buf - state->buffer;
265

Jody Goldberg's avatar
Jody Goldberg committed
266 267 268 269 270 271 272 273 274
		if (len >= state->line_len)
			skip = 1; /* skip the leading space for next line */
		else
			break;
	}

	if (state->buffer != NULL)
		state->buffer [offset] = '\0';
	return state->buffer;
275
}
Jody Goldberg's avatar
Jody Goldberg committed
276

277
static gboolean
278
applix_read_colormap (ApplixReadState *state)
279
{
Jody Goldberg's avatar
Jody Goldberg committed
280 281 282
	unsigned char *buffer, *pos, *iter, *end;
	int count;
	long numbers[6];
283 284


Jody Goldberg's avatar
Jody Goldberg committed
285
	while (NULL != (buffer = applix_get_line (state))) {
286

Jody Goldberg's avatar
Jody Goldberg committed
287
		if (!a_strncmp (buffer, "END COLORMAP"))
288 289
			return FALSE;

Jody Goldberg's avatar
Jody Goldberg committed
290
		iter = pos = buffer + strlen (buffer) - 1;
291
		for (count = 6; --count >= 0; pos = iter) {
292
			while (--iter > buffer && g_ascii_isdigit (*iter))
293 294 295 296 297
				;

			if (iter <= buffer || *iter != ' ')
				return TRUE;

Jody Goldberg's avatar
Jody Goldberg committed
298
			numbers[count] = strtol (iter+1, (char **)&end, 10);
299 300 301 302 303 304 305 306 307 308 309 310 311
			if (end != pos || numbers[count] < 0 || numbers[count] > 255)
				return TRUE;
		}
		if (numbers[0] != 0 || numbers[5] != 0)
			return TRUE;

		*pos = '\0';

		{
			int const c = numbers[1];
			int const m = numbers[2];
			int const y = numbers[3];
			int const k = numbers[4];
312
			guint8 r, g, b;
313 314 315 316 317 318 319 320

			/* From Shelf-2.1 /gui/colorcom.c:1330 */
			/* cmyk to rgb */
			r = 255 - MIN(255, c+k); /* red */
			g = 255 - MIN(255, m+k); /* green */
			b = 255 - MIN(255, y+k); /* blue */

			/* Store the result */
321
			g_ptr_array_add	(state->colors,
322
					 style_color_new_i8 (r, g, b));
323 324 325 326 327 328 329 330 331 332 333
#if 0
			printf ("'%s' %ld %ld %ld %ld\n", buffer, numbers[1],
				numbers[2], numbers[3], numbers[4]);
#endif
		}
	}

	return TRUE;
}

static gboolean
334
applix_read_typefaces (ApplixReadState *state)
335
{
Jody Goldberg's avatar
Jody Goldberg committed
336 337 338 339 340 341
	unsigned char *ptr;

	while (NULL != (ptr = applix_get_line (state))) {
		if (!a_strncmp (ptr, "END TYPEFACE TABLE"))
			return FALSE;
		g_ptr_array_add	(state->font_names, g_strdup (ptr));
342 343
	}

344 345 346
	return FALSE;
}

Morten Welinder's avatar
Morten Welinder committed
347
static GnmColor *
348
applix_get_color (ApplixReadState *state, char **buf)
349 350 351 352 353 354
{
	/* Skip 'FG' or 'BG' */
	char *start = *buf+2;
	int num = strtol (start, buf, 10);

	if (start == *buf) {
355
		(void) applix_parse_error (state, "Invalid color");
356 357 358
		return NULL;
	}

359 360
	if (num >= 0 && num < (int)state->colors->len)
		return style_color_ref (g_ptr_array_index(state->colors, num));
361 362 363 364

	return style_color_black ();
}

365 366 367
static int
applix_get_precision (char const *val)
{
Jody Goldberg's avatar
Jody Goldberg committed
368
	if ('0' <= *val && *val <= '9')
369 370 371 372 373 374
		return *val - '0';
	if (*val != 'f')
		g_warning ("APPLIX : unknow number format %c", *val);
	return 2;
}

Morten Welinder's avatar
Morten Welinder committed
375
static GnmStyle *
Jody Goldberg's avatar
Jody Goldberg committed
376
applix_parse_style (ApplixReadState *state, unsigned char **buffer)
377
{
Morten Welinder's avatar
Morten Welinder committed
378
	GnmStyle *style;
379 380
	char *start = *buffer, *tmp = start;
	gboolean is_protected = FALSE, is_invisible = FALSE;
381
	char const *format_prefix = NULL, *format_suffix = NULL;
382
	int font_id = 0; /* default */
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421

	*buffer = NULL;
	if (*tmp == 'P') {
		is_protected = TRUE;
		tmp = ++start;
	}
	if (*tmp == 'I') {
		is_invisible = TRUE;
		tmp = ++start;
	}
	if ((is_protected || is_invisible)) {
		if (*tmp != ' ') {
			(void) applix_parse_error (state, "Invalid format, protection problem");
			return NULL;
		}
		tmp = ++start;
	}

	if (*tmp != '(') {
		(void) applix_parse_error (state, "Invalid format, missing '('");
		return NULL;
	}

	while (*(++tmp) && *tmp != ')')
		;

	if (tmp[0] != ')' || tmp[1] != ' ') {
		(void) applix_parse_error (state, "Invalid format missing ')'");
		return NULL;
	}

	/* Look the descriptor string up in the hash of parsed styles */
	tmp[1] = '\0';
	style = g_hash_table_lookup (state->styles, start);
	if (style == NULL) {
		/* Parse the descriptor */
		char *sep = start;

		/* Allocate the new style */
422
		style = gnm_style_new_default ();
423

424 425
		gnm_style_set_content_locked (style, is_protected);
		gnm_style_set_content_hidden (style, is_invisible);
Jody Goldberg's avatar
Jody Goldberg committed
426

427 428 429 430 431 432 433 434
		if (sep[1] == '\'')
			sep += 2;
		else
			++sep;

		/* Formating and alignment */
		for (; *sep && *sep != '|' && *sep != ')' ; ) {

435 436 437 438 439
			if (*sep == ',') {
				++sep;
				continue;
			}

440
			if (g_ascii_isdigit (*sep)) {
441
				GnmHAlign a;
442 443 444 445 446 447
				switch (*sep) {
				case '1' : a = HALIGN_LEFT; break;
				case '2' : a = HALIGN_RIGHT; break;
				case '3' : a = HALIGN_CENTER; break;
				case '4' : a = HALIGN_FILL; break;
				default :
448
					(void) applix_parse_error (state, "Unknown horizontal alignment '%c'", *sep);
449 450
					return NULL;
				};
451
				gnm_style_set_align_h (style, a);
452 453
				++sep;
			} else if (*sep == 'V') {
454
				GnmVAlign a;
455 456 457 458 459
				switch (sep[1]) {
				case 'T' : a = VALIGN_TOP; break;
				case 'C' : a = VALIGN_CENTER; break;
				case 'B' : a = VALIGN_BOTTOM; break;
				default :
460
					(void) applix_parse_error (state, "Unknown vertical alignment '%c'", *sep);
461 462
					return NULL;
				};
463
				gnm_style_set_align_v (style, a);
464 465 466
				sep += 2;
				break;
			} else {
467
				char const *format = NULL;
468
				switch (*sep) {
469
				case 'D' : {
470 471
					int id = 0;
					char *end;
472
					static char const * const date_formats[] = {
473 474 475 476 477 478 479 480 481 482 483 484 485 486
						/*  1 */ "mmmm d, yyyy",
						/*  2 */ "mmm d, yyyy",
						/*  3 */ "d mmm yy",
						/*  4 */ "mm/dd/yy",
						/*  5 */ "dd.mm.yy",
						/*  6 */ "yyyy-mm-dd",
						/*  7 */ "yy-mm-dd",
						/*  8 */ "yyyy mm dd",
						/*  9 */ "yy mm dd",
						/* 10 */ "yyyymmdd",
						/* 11 */ "yymmdd",
						/* 12 */ "dd/mm/yy",
						/* 13 */ "dd.mm.yyyy",
						/* 14 */ "mmm dd, yyyy",
Jody Goldberg's avatar
Jody Goldberg committed
487 488
						/* 15 */ "mmmm yyyy",
						/* 16 */ "mmm.yyyy"
489 490 491 492 493 494 495 496
					};

					/* General : do nothing */
					if (sep[1] == 'N') {
						sep += 2;
						break;
					}

497
					if (!g_ascii_isdigit (sep[1]) ||
498 499
					    (0 == (id = strtol (sep+1, &end, 10))) ||
					    sep+1 == end ||
Jody Goldberg's avatar
Jody Goldberg committed
500
					    id < 1 || id > 16)
501
						(void) applix_parse_error (state, "Unknown format %d", id);
502

Morten Welinder's avatar
Morten Welinder committed
503
					format = date_formats[id - 1];
504 505 506 507 508 509 510 511 512 513 514
					sep = end;
					break;
				}
				case 'T' :
				{
					switch (sep[1]) {
					case '0' : format = "hh:mm:ss AM/PM";	break;
					case '1' : format = "hh:mm AM/PM";	break;
					case '2' : format = "hh:mm:ss";		break;
					case '3' : format = "hh:mm";		break;
					default :
515
						(void) applix_parse_error (state, "Unknown time format '%c'", sep[1]);
516 517 518 519 520
						return NULL;
					};
					sep += 2;
					break;
				}
521
				case 'G' : /* general */
522
					gnm_style_set_format_text (style, "General");
523 524 525 526

					/* What is 'Gf' ? */
					if (sep[1] == 'f')
						sep += 2;
527
					else while (g_ascii_isdigit (*(++sep)))
528
						;
529 530
					break;

531 532
				case 'C' : /* currency or comma */
					/* comma 'CO' */
533
					if (sep[1] == 'O') {
534
						++sep;
535
						format_prefix = "#,##0";
536 537
					} else
						/* FIXME : what currency to use for differnt locales */
538
						format_prefix = "$ #,##0";
539 540

					format_suffix = "";
541 542

				case 'S' : /* scientific */
543 544
					if (!format_suffix)
						format_suffix = "E+00";
545
				case 'P' : /* percentage */
546 547 548
					if (!format_suffix)
						format_suffix = "%";

549
				case 'F' : { /* fixed */
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
					static char const *zeros = "000000000";
					char *format;
					char const *prec = "", *decimal = "";
					int n_prec = applix_get_precision (++sep);

					sep++;
					if (n_prec > 0) {
						prec = zeros + 9 - n_prec;
						decimal = ".";
					}

					if (!format_prefix)
						format_prefix = "0";
					format = g_strconcat (format_prefix, decimal, prec,
							      format_suffix, NULL);

566
					gnm_style_set_format_text (style, format);
567
					g_free (format);
568
					break;
569
				}
570 571 572 573 574 575 576 577 578 579 580 581 582 583

#if 0
				/* FIXME : Add these to gnumeric ? */
				case 'GR0' : Graph ?  Seems like a truncated integer histogram
					     /* looks like crap, no need to support */

#endif
				case 'B' : if (sep[1] == '0') {
						   /* TODO : support this in gnumeric */
						   sep += 2;
						   break;
					   }
					   /* Fall through */
				default :
584
					(void) applix_parse_error (state, "Unknown format '%c'", *sep);
585 586 587
					return NULL;
				};
				if (format)
588
					gnm_style_set_format_text (style, format);
589 590 591 592 593 594 595 596 597
			}
		}

		/* Font spec */
		for (++sep ; *sep && *sep != '|' && *sep != ')' ; ) {

			/* check for the 1 character modifiers */
			switch (*sep) {
			case 'B' :
598
				gnm_style_set_font_bold (style, TRUE);
599 600 601
				++sep;
				break;
			case 'I' :
602
				gnm_style_set_font_italic (style, TRUE);
603 604 605
				++sep;
				break;
			case 'U' :
606
				gnm_style_set_font_uline (style, UNDERLINE_SINGLE);
607 608 609
				++sep;
				break;
			case 'D' :
610
				gnm_style_set_font_uline (style, UNDERLINE_DOUBLE);
611 612
				++sep;
				break;
613 614 615 616 617 618
			case 'f' :
				if (sep[1] == 'g' ) {
					/* TODO : what is this ?? */
					sep += 2;
					break;
				};
619
				(void) applix_parse_error (state, "Unknown font modifier 'f%c'", sep[1]);
620 621 622 623
				return NULL;

			case 'F' :
				if (sep[1] == 'G' ) {
Morten Welinder's avatar
Morten Welinder committed
624
					GnmColor *color = applix_get_color (state, &sep);
625 626
					if (color == NULL)
						return NULL;
627
					gnm_style_set_font_color (style, color);
628 629
					break;
				}
630
				(void) applix_parse_error (state, "Unknown font modifier F%c", sep[1]);
631 632 633 634 635 636 637
				return NULL;

			case 'P' : {
				char *start = ++sep;
				double size = strtod (start, &sep);

				if (start != sep && size > 0.) {
638
					gnm_style_set_font_size (style, size / gnm_app_dpi_to_pixels ());
639 640
					break;
				}
641
				(void) applix_parse_error (state, "Invalid font size '%s", start);
642 643 644
				return NULL;
			}

645 646 647 648 649 650 651
			case 'W' :
				if (sep[1] == 'T') {
					/* FIXME : What is WTO ?? */
					if (sep[2] == 'O') {
						sep +=3;
						break;
					}
652
					gnm_style_set_wrap_text (style, TRUE);
653 654 655
					sep +=2;
					break;
				}
656
				(void) applix_parse_error (state, "Unknown font modifier W%c", sep[1]);
657 658 659 660
				return NULL;

			case 'T' :
				if (sep[1] == 'F') {
661
					/* be a font ID numbered from 0 */
662
					char *start = (sep += 2);
663

664 665 666
					font_id = strtol (start, &sep, 10);
					if (start == sep || font_id < 0 || font_id >= (int)state->font_names->len)
						(void) applix_parse_error (state, "Unknown font index %s", start);
667 668 669 670 671 672 673 674 675 676 677 678 679 680
					break;
				}


			default :
				(void) applix_parse_error (state, "Unknown font modifier");
				return NULL;
			};

			if (*sep == ',')
				++sep;
		}

		if (*sep != '|' && *sep != ')') {
681
			(void) applix_parse_error (state, "Invalid font specification");
682 683 684
			return NULL;
		}

685
		gnm_style_set_font_name (style, g_ptr_array_index (state->font_names, font_id));
686

687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
		/* Background, pattern, and borders */
		for (++sep ; *sep && *sep != ')' ; ) {

			if (sep[0] == 'S' && sep[1] == 'H')  {
				/* A map from applix patten
				 * indicies to gnumeric.
				 */
				static int const map[] = { 0,
					1,  6, 5,  4,  3, 2, 25,
					24, 14, 13, 17, 16, 15, 11,
					19, 20, 21, 22, 23,
				};
				char *end;
				int num = strtol (sep += 2, &end, 10);

702
				if (sep == end || 0 >= num || num >= (int)G_N_ELEMENTS (map)) {
703
					(void) applix_parse_error (state, "Unknown pattern %s", sep);
704 705 706 707
					return NULL;
				}

				num = map[num];
708
				gnm_style_set_pattern (style, num);
709 710 711
				sep = end;

				if (sep[0] == 'F' && sep[1] == 'G' ) {
Morten Welinder's avatar
Morten Welinder committed
712
					GnmColor *color = applix_get_color (state, &sep);
713 714
					if (color == NULL)
						return NULL;
715
					gnm_style_set_pattern_color (style, color);
716 717 718
				}

				if (sep[0] == 'B' && sep[1] == 'G') {
Morten Welinder's avatar
Morten Welinder committed
719
					GnmColor *color = applix_get_color (state, &sep);
720 721
					if (color == NULL)
						return NULL;
722
					gnm_style_set_back_color (style, color);
723
				}
724 725
			} else if (sep[0] == 'T' || sep[0] == 'B' || sep[0] == 'L' || sep[0] == 'R') {
				/* A map from applix border indicies to gnumeric. */
726
				static StyleBorderType const map[] = {0,
727 728 729 730 731 732 733
					STYLE_BORDER_THIN,
					STYLE_BORDER_MEDIUM,
					STYLE_BORDER_THICK,
					STYLE_BORDER_DASHED,
					STYLE_BORDER_DOUBLE
				};

Morten Welinder's avatar
Morten Welinder committed
734
				GnmColor *color;
735
				GnmStyleElement const type =
736 737 738 739 740 741 742 743
					(sep[0] == 'T') ? MSTYLE_BORDER_TOP :
					(sep[0] == 'B') ? MSTYLE_BORDER_BOTTOM :
					(sep[0] == 'L') ? MSTYLE_BORDER_LEFT : MSTYLE_BORDER_RIGHT;
				StyleBorderOrientation const orient = (sep[0] == 'T' || sep[0] == 'B')
					? STYLE_BORDER_HORIZONTAL : STYLE_BORDER_VERTICAL;
				char *end;
				int num = strtol (++sep, &end, 10);

744
				if (sep == end || 0 >= num || num >= (int)G_N_ELEMENTS (map)) {
745
					(void) applix_parse_error (state, "Unknown border style %s", sep);
746 747 748 749 750
					return NULL;
				}
				sep = end;

				if (sep[0] == 'F' && sep[1] == 'G' ) {
751
					color = applix_get_color (state, &sep);
752 753 754 755 756
					if (color == NULL)
						return NULL;
				} else
					color = style_color_black ();

757
				gnm_style_set_border (style, type,
758 759 760 761 762 763
						   style_border_fetch (map[num], color, orient));
			}

			if (*sep == ',')
				++sep;
			else if (*sep != ')') {
764
				(void) applix_parse_error (state, "Invalid pattern, background, or border");
765 766 767 768 769
				return NULL;
			}
		}

		if (*sep != ')') {
770
			(void) applix_parse_error (state, "Invalid pattern or background");
771 772 773 774 775 776 777 778 779 780
			return NULL;
		}

		/* Store the newly parsed style along with its descriptor */
		g_hash_table_insert (state->styles, g_strdup (start), style);
	}

	g_return_val_if_fail (style != NULL, NULL);

	*buffer = tmp + 2;
781
	gnm_style_ref (style);
782 783 784
	return style;
}

785
static gboolean
786
applix_read_attributes (ApplixReadState *state)
787 788
{
	int count = 0;
Jody Goldberg's avatar
Jody Goldberg committed
789
	unsigned char *ptr, *tmp;
Morten Welinder's avatar
Morten Welinder committed
790
	GnmStyle *style;
791

Jody Goldberg's avatar
Jody Goldberg committed
792 793 794
	while (NULL != (ptr = applix_get_line (state))) {
		if (!a_strncmp (ptr, "Attr Table End"))
			return FALSE;
795

Jody Goldberg's avatar
Jody Goldberg committed
796
		if (ptr [0] != '<')
797 798 799 800
			return applix_parse_error (state, "Invalid attribute");

		/* TODO : The first style seems to be a different format */
		if (count++) {
Jody Goldberg's avatar
Jody Goldberg committed
801
			tmp = ptr + 1;
802 803 804 805 806 807 808 809
			style = applix_parse_style (state, &tmp);
			if (style == NULL || *tmp != '>')
				return applix_parse_error (state, "Invalid attribute");
			g_ptr_array_add	(state->attrs, style);
		}
	}

	/* NOTREACHED */
810
	return FALSE;
811 812 813
}

static Sheet *
814 815 816 817 818 819
applix_fetch_sheet (ApplixReadState *state, char const *name)
{
	Sheet *sheet = workbook_sheet_by_name (state->wb, name);

	if (sheet == NULL) {
		sheet = sheet_new (state->wb, name);
820
		workbook_sheet_attach (state->wb, sheet);
821
		g_object_set (sheet, "zoom-factor", state->zoom / 100.0, NULL);
822 823 824 825 826 827 828 829 830
		sheet_flag_recompute_spans (sheet);
	}

	return sheet;
}

static Sheet *
applix_parse_sheet (ApplixReadState *state, unsigned char **buffer,
		    char const separator)
831 832 833 834
{
	Sheet *sheet;

	/* Get sheet name */
Morten Welinder's avatar
Morten Welinder committed
835
	char *tmp = strchr (*buffer, separator);
836 837 838 839 840 841 842

	if (tmp == NULL) {
		(void) applix_parse_error (state, "Invalid sheet name.");
		return NULL;
	}

	*tmp = '\0';
843
	sheet = applix_fetch_sheet (state, *buffer);
844 845 846 847 848
	*buffer = tmp+1;
	return sheet;
}

static char *
Jody Goldberg's avatar
Jody Goldberg committed
849
applix_parse_cellref (ApplixReadState *state, unsigned char *buffer,
Jody Goldberg's avatar
Jody Goldberg committed
850
		      Sheet **sheet, GnmCellPos *pos,
Morten Welinder's avatar
Morten Welinder committed
851
		      char const separator)
852
{
853
	*sheet = applix_parse_sheet (state, &buffer, separator);
854 855

	/* Get cell addr */
856
	if (*sheet) {
857
		buffer = (unsigned char *)cellpos_parse (buffer, pos, FALSE);
858 859 860
		if (buffer)
			return buffer;
	}
861 862

	*sheet = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
863
	pos->col = pos->row = -1;
864 865 866
	return NULL;
}

867 868 869 870 871 872 873 874 875 876
static int
applix_height_to_pixels (int height)
{
	return height+4;
}
static int
applix_width_to_pixels (int width)
{
	return width*8 + 3;
}
877

878 879 880 881 882 883 884 885 886 887 888
static int
applix_read_current_view (ApplixReadState *state, unsigned char *buffer)
{
	/* What is this ? */
	unsigned char *ptr;
	while (NULL != (ptr = applix_get_line (state)))
	       if (!a_strncmp (ptr, "End View, Name: ~Current~"))
		       return 0;
	return -1;
}

889
static int
Jody Goldberg's avatar
Jody Goldberg committed
890
applix_read_view (ApplixReadState *state, unsigned char *buffer)
891
{
Jody Goldberg's avatar
Jody Goldberg committed
892 893
	Sheet *sheet = NULL;
	unsigned char *name = buffer + 19;
894
	unsigned char *tmp;
Jody Goldberg's avatar
Jody Goldberg committed
895
	gboolean ignore;
Jody Goldberg's avatar
Jody Goldberg committed
896

897 898 899 900
	tmp = strchr (name, ':');
	if (tmp == NULL)
		return 0;
	*tmp =  '\0';
901

902
	ignore = tmp[1] != '~';
903 904 905
	if (!ignore)
		state->sheet_order = g_slist_prepend (state->sheet_order,
			applix_fetch_sheet (state, name));
Jody Goldberg's avatar
Jody Goldberg committed
906

Jody Goldberg's avatar
Jody Goldberg committed
907
	while (NULL != (buffer = applix_get_line (state))) {
Jody Goldberg's avatar
Jody Goldberg committed
908 909 910
		if (!a_strncmp (buffer, "View End, Name: ~"))
			break;
		if (ignore)
Jody Goldberg's avatar
Jody Goldberg committed
911 912
			continue;

Jody Goldberg's avatar
Jody Goldberg committed
913
		if (!a_strncmp (buffer, "View Top Left: ")) {
Jody Goldberg's avatar
Jody Goldberg committed
914
			GnmCellPos pos;
Jody Goldberg's avatar
Jody Goldberg committed
915
			if (applix_parse_cellref (state, buffer+15, &sheet, &pos, ':'))
916 917
				sv_set_initial_top_left (sheet_get_view (sheet, state->wb_view),
							 pos.col, pos.row);
Jody Goldberg's avatar
Jody Goldberg committed
918
		} else if (!a_strncmp (buffer, "View Open Cell: ")) {
Jody Goldberg's avatar
Jody Goldberg committed
919
			GnmCellPos pos;
Jody Goldberg's avatar
Jody Goldberg committed
920 921 922 923
			if (applix_parse_cellref (state, buffer+16, &sheet, &pos, ':'))
				sv_selection_set (sheet_get_view (sheet, state->wb_view),
						  &pos, pos.col, pos.row, pos.col, pos.row);
		} else if (!a_strncmp (buffer, "View Default Column Width ")) {
924 925 926 927 928 929
			char *ptr, *tmp = buffer + 26;
			int width = strtol (tmp, &ptr, 10);
			if (tmp == ptr || width <= 0)
				return applix_parse_error (state, "Invalid default column width");

			sheet_col_set_default_size_pixels (sheet,
930
				applix_width_to_pixels (width));
Jody Goldberg's avatar
Jody Goldberg committed
931
		} else if (!a_strncmp (buffer, "View Default Row Height: ")) {
932 933 934 935 936 937 938
			char *ptr, *tmp = buffer + 25;
			int height = strtol (tmp, &ptr, 10);
			if (tmp == ptr || height <= 0)
				return applix_parse_error (state, "Invalid default row height");

			/* height + one for the grid line */
			sheet_row_set_default_size_pixels (sheet,
939
				applix_height_to_pixels (height));
Jody Goldberg's avatar
Jody Goldberg committed
940
		} else if (!a_strncmp (buffer, "View Row Heights: ")) {
941 942 943 944 945
			char *ptr = buffer + 17;
			do {
				int row, height;
				char *tmp;

Jody Goldberg's avatar
Jody Goldberg committed
946
				row = strtol (tmp = ptr + 1, &ptr, 10) - 1;
947
				if (tmp == ptr || row < 0 || *ptr != ':')
948
					return applix_parse_error (state, "Invalid row size row number");
Jody Goldberg's avatar
Jody Goldberg committed
949
				height = strtol (tmp = ptr + 1, &ptr, 10);
950 951 952 953
				if (height >= 32768)
					height -= 32768;

				if (tmp == ptr || height <= 0)
954 955 956 957 958
					return applix_parse_error (state, "Invalid row size");

				/* These seem to assume
				 * top margin 2
				 * bottom margin 1
959
				 * size in pixels = val -32768 (sometimes ??)
960
				 */
961
				sheet_row_set_size_pixels (sheet, row,
962
							  applix_height_to_pixels (height),
963
							  TRUE);
964
			} while (ptr[0] == ' ' && g_ascii_isdigit (ptr[1]));
Jody Goldberg's avatar
Jody Goldberg committed
965
		} else if (!a_strncmp (buffer, "View Column Widths: ")) {
Jody Goldberg's avatar
Jody Goldberg committed
966 967 968 969
			char const *ptr = buffer + 19;
			char const *tmp;
			int col, width;
			unsigned char dummy;
970

Jody Goldberg's avatar
Jody Goldberg committed
971
			do {
972
				ptr = col_parse (tmp = ptr + 1, &col, &dummy);
973
				if (!ptr || *ptr != ':')
974
					return applix_parse_error (state, "Invalid column");
Jody Goldberg's avatar
Jody Goldberg committed
975
				width = strtol (tmp = ptr + 1, (char **)&ptr, 10);
976 977 978 979 980 981 982 983 984
				if (tmp == ptr || width <= 0)
					return applix_parse_error (state, "Invalid column size");

				/* These seem to assume
				 * pixels = 8*width + 3 for the grid lines and margins
				 */
				sheet_col_set_size_pixels (sheet, col,
							   applix_width_to_pixels (width),
							   TRUE);
985
			} while (ptr[0] == ' ' && g_ascii_isalpha (ptr[1]));
Jody Goldberg's avatar
Jody Goldberg committed
986
		}
987 988
	}

Jody Goldberg's avatar
Jody Goldberg committed
989
	return 0;
990 991
}

992 993 994 995
static int
applix_read_cells (ApplixReadState *state)
{
	Sheet *sheet;
Morten Welinder's avatar
Morten Welinder committed
996
	GnmStyle *style;
997
	GnmCell *cell;
Jody Goldberg's avatar
Jody Goldberg committed
998
	GnmCellPos pos;
Morten Welinder's avatar
Morten Welinder committed
999
	GnmParseError  perr;
Jody Goldberg's avatar
Jody Goldberg committed
1000
	unsigned char content_type, *tmp, *ptr;
1001

Jody Goldberg's avatar
Jody Goldberg committed
1002 1003
	while (NULL != (ptr = applix_get_line (state))) {
		gboolean const val_is_string = (ptr[0] != '\0' && ptr[1] == '\'');
1004

Jody Goldberg's avatar
Jody Goldberg committed
1005 1006
	       if (!a_strncmp (ptr, "*END SPREADSHEETS"))
		       break;
1007

Jody Goldberg's avatar
Jody Goldberg committed
1008 1009
		/* Parse formatting */
		style = applix_parse_style (state, &ptr);
1010 1011 1012
		if (style == NULL)
			return -1;
		if (ptr == NULL) {
1013
			gnm_style_unref (style);
1014 1015 1016 1017
			return -1;
		}

		/* Get cell */
Jody Goldberg's avatar
Jody Goldberg committed
1018
		ptr = applix_parse_cellref (state, ptr, &sheet, &pos, '!');
1019
		if (ptr == NULL) {
1020
			gnm_style_unref (style);
1021 1022
			return applix_parse_error (state, "Expression did not specify target cell");
		}
Jody Goldberg's avatar
Jody Goldberg committed
1023
		cell = sheet_cell_fetch (sheet, pos.col, pos.row);
1024 1025

		/* Apply the formating */
Jody Goldberg's avatar
Jody Goldberg committed
1026
		sheet_style_set_pos (sheet, pos.col, pos.row, style);
1027 1028 1029
		content_type = *ptr;
		switch (content_type) {
		case ';' : /* First of a shared formula */
1030
		case '.' : { /* instance of a shared formula */
Morten Welinder's avatar
Morten Welinder committed
1031
			GnmParsePos	 pos;
1032
			GnmExpr	const	*expr;
Jody Goldberg's avatar
Jody Goldberg committed
1033 1034
			GnmValue		*val = NULL;
			GnmRange		 r;
1035 1036 1037 1038
			char *expr_string;

			ptr = applix_parse_value (ptr+2, &expr_string);

1039 1040 1041 1042
			/* Just in case something failed */
			if (ptr == NULL)
				return -1;

1043
			if (!val_is_string)
1044 1045
				/* Does it match any formats (use default date convention) */
				val = format_match (ptr, NULL, NULL);
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055

			if (val == NULL)
				/* TODO : Could this happen ? */
				val = value_new_string (ptr);

#if 0
			printf ("\'%s\'\n\'%s\'\n", ptr, expr_string);
#endif

			if (content_type == ';') {
1056
				gboolean	is_array = FALSE;
1057 1058 1059 1060

				if (*expr_string == '~') {
					Sheet *start_sheet, *end_sheet;
					tmp = applix_parse_cellref (state, expr_string+1, &start_sheet,
Jody Goldberg's avatar
Jody Goldberg committed
1061
								    &r.start, ':');
1062 1063 1064 1065
					if (start_sheet == NULL || tmp == NULL || tmp[0] != '.' || tmp[1] != '.') {
						(void) applix_parse_error (state, "Invalid array expression");
						continue;
					}
1066 1067

					tmp = applix_parse_cellref (state, tmp+2, &end_sheet,
Jody Goldberg's avatar
Jody Goldberg committed
1068
								    &r.end, ':');
1069 1070 1071 1072
					if (end_sheet == NULL || tmp == NULL || tmp[0] != '~') {
						(void) applix_parse_error (state, "Invalid array expression");
						continue;
					}
1073

1074 1075 1076 1077
					if (start_sheet != end_sheet) {
						(void) applix_parse_error (state, "3D array functions are not supported.");
						continue;
					}
1078 1079 1080 1081 1082

					is_array = TRUE;
					expr_string = tmp+3; /* ~addr~<space><space>=expr */
				}

1083 1084 1085 1086
				/* We need to continue at all costs so that the
				 * rest of the sheet can be parsed. If we quit, then trailing
				 * 'Formula ' lines confuse the parser
				 */
1087
				if (*expr_string != '=' && *expr_string != '+') {
1088 1089 1090 1091 1092 1093
					(void) applix_parse_error (state, _("Expression did not start with '=' ? '%s'"),
								   expr_string);
					expr = gnm_expr_new_constant (value_new_string (expr_string));
				} else
					expr = gnm_expr_parse_str (expr_string+1,
						parse_pos_init_cell (&pos, cell),
1094 1095 1096
								   GNM_EXPR_PARSE_DEFAULT,
								   state->exprconv,
								   parse_error_init (&perr));
1097

1098
				if (expr == NULL) {
1099 1100
					(void) applix_parse_error (state, _("%s!%s : unable to parse '%s'\n     %s"),
								   cell->base.sheet->name_quoted, cell_name (cell),
1101
								   expr_string, perr.err->message);
1102 1103 1104
					parse_error_free (&perr);
					expr = gnm_expr_new_constant (value_new_string (expr_string));
				} else if (is_array) {
1105
					gnm_expr_ref (expr);
1106
					cell_set_array_formula (sheet,
1107 1108 1109
								r.start.col, r.start.row,
								r.end.col, r.end.row,
								expr);
1110
					cell_assign_value (cell, val);
1111
				} else
1112
					cell_set_expr_and_value (cell, expr, val, TRUE);
1113

1114
				if (!applix_get_line (state) ||
Jody Goldberg's avatar
Jody Goldberg committed
1115
				    a_strncmp (state->buffer, "Formula: ")) {
1116
					(void) applix_parse_error (state, "Missing formula ID");
1117 1118
					continue;
				}
1119

1120
				ptr = state->buffer + 9;
1121 1122

				/* Store the newly parsed expresion along with its descriptor */
1123 1124
				g_hash_table_insert (state->exprs, g_strdup (ptr),
						     (gpointer)expr);
1125
			} else {
1126
				char const *key = expr_string + strlen (expr_string);
1127
				while (key > expr_string && !g_ascii_isspace (key[-1]))
1128
					key--;
1129
#if 0
1130
				printf ("Shared '%s'\n", expr_string);
1131
#endif
1132
				expr = g_hash_table_lookup (state->exprs, key);
1133
				cell_set_expr_and_value (cell, expr, val, TRUE);
1134 1135 1136 1137
			}
			break;
		}

1138
		case ':' : { /* simple value */
Jody Goldberg's avatar
Jody Goldberg committed
1139
			GnmValue *val = NULL;
1140 1141 1142 1143 1144

			ptr += 2;
#if 0
			printf ("\"%s\" %d\n", ptr, val_is_string);
#endif
1145
			/* Does it match any formats (use default date convention) */
1146
			if (!val_is_string)
1147
				val = format_match (ptr, NULL, NULL);
1148 1149 1150 1151
			if (val == NULL)
				val = value_new_string (ptr);

			if (cell_is_array (cell))
1152
				cell_assign_value (cell, val);
1153
			else
1154
				cell_set_value (cell, val);
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
			break;
		}

		default :
			g_warning ("Unknown cell type '%c'", content_type);
		};
	}

	return 0;
}

Jody Goldberg's avatar
Jody Goldberg committed
1166 1167 1168 1169
static int
applix_read_row_list (ApplixReadState *state, unsigned char *ptr)
{
	unsigned char *tmp;
Jody Goldberg's avatar
Jody Goldberg committed
1170
	GnmRange	r;
1171
	Sheet *sheet = applix_parse_sheet (state, &ptr, ' ');
Jody Goldberg's avatar
Jody Goldberg committed
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193

	if (ptr == NULL)
		return -1;
	if (*ptr != '!')
		return applix_parse_error (state, "Invalid row format");

	r.start.row = r.end.row = strtol (++ptr, (char **)&tmp, 10) - 1;
	if (tmp == ptr || r.start.row < 0 || tmp[0] != ':' || tmp[1] != ' ')
		return applix_parse_error (state, "Invalid row format row number");

	++tmp;
	do {
		unsigned attr_index;

		r.start.col = strtol (ptr = tmp+1, (char **)&tmp, 10);
		if (tmp == ptr || r.start.col < 0 || tmp[0] != '-')
			return applix_parse_error (state, "Invalid row format start col");
		r.end.col = strtol (ptr = tmp+1, (char **)&tmp, 10);
		if (tmp == ptr || r.end.col < 0 || tmp[0] != ':')
			return applix_parse_error (state, "Invalid row format end col");
		attr_index = strtol (ptr = tmp+1, (char **)&tmp, 10);
		if (tmp != ptr && attr_index >= 2 && attr_index < state->attrs->len+2) {
Morten Welinder's avatar
Morten Welinder committed
1194
			GnmStyle *style = g_ptr_array_index(state->attrs, attr_index-2);
1195
			gnm_style_ref (style);
Jody Goldberg's avatar
Jody Goldberg committed
1196 1197 1198 1199 1200
			sheet_style_set_range (sheet, &r, style);
		} else if (attr_index != 1) /* TODO : What the hell is attr 1 ?? */
			return applix_parse_error (state, "Invalid row format attr index");

	/* Just for kicks they added a trailing space */
1201
	} while (tmp[0] && g_ascii_isdigit (tmp[1]));
Jody Goldberg's avatar
Jody Goldberg committed
1202 1203 1204 1205

	return 0;
}

1206
static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
1207 1208 1209
applix_read_sheet_table (ApplixReadState *state)
{
	unsigned char *ptr;
1210 1211
	unsigned char *std_name, *real_name;
	while (NULL != (ptr = applix_get_line (state))) {
Jody Goldberg's avatar
Jody Goldberg committed
1212
	       if (!a_strncmp (ptr, "END SHEETS TABLE"))
1213
		       return FALSE;
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232

	       /* Sheet A: ~Foo~ */
	       std_name = ptr + 6;
	       ptr = strchr (std_name, ':');
	       if (ptr == NULL)
		       continue;
	       *ptr = '\0';

	       real_name = ptr + 3;
	       ptr = strchr (real_name, '~');
	       if (ptr == NULL)
		       continue;
	       *ptr = '\0';

	       state->std_names  = g_slist_prepend (state->std_names,
						    g_strdup (std_name));
	       state->real_names = g_slist_prepend (state->real_names,
						    g_strdup (real_name));
	}
1233
	return TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
1234 1235
}

1236
static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
1237 1238 1239 1240 1241
applix_read_header_footer (ApplixReadState *state)
{
	unsigned char *ptr;
	while (NULL != (ptr = applix_get_line (state)))
	       if (!a_strncmp (ptr, "Headers And Footers End"))
1242 1243
		       return FALSE;
	return TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
1244 1245
}

1246
static gboolean
1247
applix_read_absolute_name (ApplixReadState *state, char *buffer)
1248 1249
{
	char *end;
Jody Goldberg's avatar
Jody Goldberg committed
1250
	GnmRangeRef ref;
Morten Welinder's avatar
Morten Welinder committed
1251
	GnmParsePos pp;
1252
	GnmExpr const *expr;
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262

	/* .ABCDe. Coordinate: A:B2..A:C4 */
	/* Spec guarantees that there are no dots in the name */
	buffer = strchr (buffer, '.');
	if (buffer == NULL)
		return TRUE;
	end = strchr (++buffer, '.');
	if (end == NULL)
		return TRUE;
	*end = '\0';
1263 1264 1265 1266
	end = strchr (end + 1, ':');
	if (end == NULL)
		return TRUE;
	applix_rangeref_parse (&ref, end+2,
Jody Goldberg's avatar
Jody Goldberg committed
1267 1268
		parse_pos_init (&pp, state->wb, NULL, 0, 0),
		state->exprconv);
1269 1270 1271 1272
	ref.a.col_relative = ref.b.col_relative =
		ref.a.row_relative = ref.b.row_relative = FALSE;

	expr = gnm_expr_new_constant (value_new_cellrange_unsafe (&ref.a, &ref.b));
Jody Goldberg's avatar
Jody Goldberg committed
1273
	expr_name_add (&pp, buffer, expr, NULL, TRUE, NULL);
1274

1275 1276 1277 1278
	return FALSE;
}

static gboolean
1279
applix_read_relative_name (ApplixReadState *state, char *buffer)
1280
{
1281 1282
	int dummy;
	char *end;
Jody Goldberg's avatar
Jody Goldberg committed
1283
	GnmRangeRef ref, flag;
Morten Welinder's avatar
Morten Welinder committed
1284
	GnmParsePos pp;
1285 1286
	GnmExpr const *expr;

1287 1288
	/* .abcdE. tCol:0 tRow:0 tSheet:0 bCol:1 bRow:2 bSheet: 0 tColAbs:0 tRowAbs:0 tSheetAbs:1 bColAbs:0 bRowAbs:0 bSheetAbs:1 */
	/* Spec guarantees that there are no dots in the name */
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
	buffer = strchr (buffer, '.');
	if (buffer == NULL)
		return TRUE;
	end = strchr (++buffer, '.');
	if (end == NULL)
		return TRUE;
	*end = '\0';
	if (12 != sscanf (end + 2,
			  " tCol:%d tRow:%d tSheet:%d bCol:%d bRow:%d bSheet: %d tColAbs:%d tRowAbs:%d tSheetAbs:%d bColAbs:%d bRowAbs:%d bSheetAbs:%d",
			  &ref.a.col, &ref.a.row, &dummy, &ref.b.col, &ref.b.row, &dummy,
			  &flag.a.col, &flag.a.row, &dummy, &flag.b.col, &flag.b.row, &dummy))
		return TRUE;

	ref.a.col_relative = (flag.a.col == 0);
	ref.b.col_relative = (flag.b.col == 0);
	ref.a.row_relative = (flag.a.row == 0);
	ref.b.row_relative = (flag.b.row == 0);

	ref.a.sheet = ref.b.sheet = NULL;
	expr = gnm_expr_new_constant (value_new_cellrange_unsafe (&ref.a, &ref.b));
	parse_pos_init (&pp, state->wb, NULL,
		MAX (-ref.a.col, 0), MAX (-ref.a.row, 0));
Jody Goldberg's avatar
Jody Goldberg committed
1311
	expr_name_add (&pp, buffer, expr, NULL, TRUE, NULL);
1312

1313 1314 1315 1316 1317 1318
	return FALSE;
}

#define ABS_NAMED_RANGE	"Named Range, Name:"
#define REL_NAMED_RANGE	"Relative Named Range, Name:"

1319 1320 1321 1322
static int
applix_read_impl (ApplixReadState *state)
{
	Sheet *sheet;
Jody Goldberg's avatar
Jody Goldberg committed
1323
	GnmCellPos pos;
1324
	int ext_links = -1;
Jody Goldberg's avatar
Jody Goldberg committed
1325
	unsigned char *real_name = NULL;
1326 1327
	char top_cell_addr[30] = "";
	char cur_cell_addr[30] = "";
Jody Goldberg's avatar
Jody Goldberg committed
1328
	unsigned char *buffer;
1329 1330 1331 1332 1333
	char default_text_format[128] = "";
	char default_number_format[128] = "";
	int def_col_width = -1;
	int win_width = -1;
	int win_height = -1;
1334

Jody Goldberg's avatar
Jody Goldberg committed
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364