X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fgnumeric-reader.c;h=07b88163398f7df9a4b6aa7380b5fe6f0e607369;hb=1509c6773d7302a2753c4f47b3e52fc5e3cca185;hp=c36a6832537a086ddd0123ad509210c213ef9b2f;hpb=c13375ebe886fc3ed5ce70a260bb2b01cebb4b1f;p=pspp diff --git a/src/data/gnumeric-reader.c b/src/data/gnumeric-reader.c index c36a683253..07b8816339 100644 --- a/src/data/gnumeric-reader.c +++ b/src/data/gnumeric-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. 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 @@ -14,58 +14,58 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ - - #include -#include +#include "libpspp/message.h" +#include "libpspp/misc.h" + +#include "gl/minmax.h" +#include "gl/c-strtod.h" #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) (msgid) +#include "spreadsheet-reader.h" + +#include "c-xvasprintf.h" #if !GNM_SUPPORT struct casereader * -gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) +gnumeric_open_reader (struct spreadsheet_read_info *gri, struct spreadsheet_read_options *opts, struct dictionary **dict) { - msg (ME, _("Support for Gnumeric files was not compiled into this installation of PSPP")); + msg (ME, _("Support for %s files was not compiled into this installation of PSPP"), "Gnumeric"); return NULL; } #else -#include -#include -#include -#include -#include -#include -#include +#include "data/gnumeric-reader.h" +#include +#include #include #include #include -#include -#include -#include - -#include - -#include "gnumeric-reader.h" -#include -#include +#include "data/case.h" +#include "data/casereader-provider.h" +#include "data/dictionary.h" +#include "data/identifier.h" +#include "data/value.h" +#include "data/variable.h" +#include "libpspp/i18n.h" +#include "libpspp/str.h" +#include "gl/xalloc.h" static void gnm_file_casereader_destroy (struct casereader *, void *); -static bool gnm_file_casereader_read (struct casereader *, void *, - struct ccase *); +static struct ccase *gnm_file_casereader_read (struct casereader *, void *); -static struct casereader_class gnm_file_casereader_class = +static const struct casereader_class gnm_file_casereader_class = { gnm_file_casereader_read, gnm_file_casereader_destroy, @@ -73,116 +73,104 @@ static struct casereader_class gnm_file_casereader_class = NULL, }; -/* Convert a string, which is an integer encoded in base26 - IE, A=0, B=1, ... Z=25 to the integer it represents. - ... except that in this scheme, digits with an exponent - greater than 1 are implicitly incremented by 1, so - AA = 0 + 1*26, AB = 1 + 1*26, - ABC = 2 + 2*26 + 1*26^2 .... -*/ -static int -pseudo_base26 (const char *str) -{ - int i; - int multiplier = 1; - int result = 0; - int len = strlen (str); - - for ( i = len - 1 ; i >= 0; --i) - { - int mantissa = (str[i] - 'A'); - - if ( mantissa < 0 || mantissa > 25 ) - return -1; - - if ( i != len - 1) - mantissa++; - - result += mantissa * multiplier; - - multiplier *= 26; - } - - return result; -} - - - -/* Convert a cell reference in the form "A1:B2", to - integers. A1 means column zero, row zero. - B1 means column 1 row 0. AA1 means column 26, row 0. -*/ -static bool -convert_cell_ref (const char *ref, - int *col0, int *row0, - int *coli, int *rowi) -{ - char startcol[5]; - char stopcol [5]; - - int startrow; - int stoprow; - - int n = sscanf (ref, "%4[a-zA-Z]%d:%4[a-zA-Z]%d", - startcol, &startrow, - stopcol, &stoprow); - if ( n != 4) - return false; - - str_uppercase (startcol); - *col0 = pseudo_base26 (startcol); - str_uppercase (stopcol); - *coli = pseudo_base26 (stopcol); - *row0 = startrow - 1; - *rowi = stoprow - 1 ; - - return true; -} - - enum reader_state { - STATE_INIT = 0, /* Initial state */ + STATE_PRE_INIT = 0, /* Initial state */ + STATE_SHEET_COUNT, /* Found the sheet index */ + STATE_INIT , /* Other Initial state */ STATE_SHEET_START, /* Found the start of a sheet */ STATE_SHEET_NAME, /* Found the sheet name */ STATE_MAXROW, + STATE_MAXCOL, STATE_SHEET_FOUND, /* Found the sheet that we actually want */ STATE_CELLS_START, /* Found the start of the cell array */ STATE_CELL /* Found a cell */ }; +struct sheet_detail +{ + xmlChar *name; + + int start_col; + int stop_col; + int start_row; + int stop_row; + + int maxcol; + int maxrow; +}; + struct gnumeric_reader { + struct spreadsheet spreadsheet; + + /* The libxml reader for this instance */ xmlTextReaderPtr xtr; + /* An internal state variable */ enum reader_state state; + int row; int col; + int min_col; int node_type; - int sheet_index; - - - const xmlChar *target_sheet; - int target_sheet_index; + int current_sheet; - int start_row; int start_col; - int stop_row; int stop_col; + int start_row; + int stop_row; + + struct sheet_detail *sheets; + const xmlChar *target_sheet; + int target_sheet_index; - size_t value_cnt; + struct caseproto *proto; struct dictionary *dict; - struct ccase first_case; + struct ccase *first_case; bool used_first_case; }; + +const char * +gnumeric_get_sheet_name (struct spreadsheet *s, int n) +{ + struct gnumeric_reader *gr = (struct gnumeric_reader *) s; + assert (n < s->n_sheets); + + return gr->sheets[n].name; // Kludge: Assumes the encoding is utf8 +} + + static void process_node (struct gnumeric_reader *r); -#define _xml(X) (const xmlChar *)(X) -#define _xmlchar_to_int(X) atoi((const char *)X) +char * +gnumeric_get_sheet_range (struct spreadsheet *s, int n) +{ + int ret; + struct gnumeric_reader *gr = (struct gnumeric_reader *) s; + + assert (n < s->n_sheets); + + while ( + (gr->sheets[n].stop_col == -1) + && + (1 == (ret = xmlTextReaderRead (gr->xtr))) + ) + { + process_node (gr); + } + + return create_cell_ref ( + gr->sheets[n].start_col, + gr->sheets[n].start_row, + gr->sheets[n].stop_col, + gr->sheets[n].stop_row); +} + static void gnm_file_casereader_destroy (struct casereader *reader UNUSED, void *r_) @@ -193,11 +181,24 @@ gnm_file_casereader_destroy (struct casereader *reader UNUSED, void *r_) if ( r->xtr) xmlFreeTextReader (r->xtr); + r->xtr = NULL; if ( ! r->used_first_case ) - case_destroy (&r->first_case); + case_unref (r->first_case); + + caseproto_unref (r->proto); + +#if 0 + for (i = 0; i < r->spreadsheet.n_sheets; ++i) + { + xmlFree (r->sheets[i].name); + } + + free (r->sheets); + free (r); +#endif } static void @@ -212,10 +213,46 @@ process_node (struct gnumeric_reader *r) switch ( r->state) { + case STATE_PRE_INIT: + r->current_sheet = -1; + if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) && + XML_READER_TYPE_ELEMENT == r->node_type) + { + r->state = STATE_SHEET_COUNT; + } + break; + + case STATE_SHEET_COUNT: + if (0 == xmlStrcasecmp (name, _xml("gnm:SheetName")) && + XML_READER_TYPE_ELEMENT == r->node_type) + { + ++r->current_sheet; + if (r->current_sheet + 1 > r->spreadsheet.n_sheets) + { + struct sheet_detail *sd ; + r->sheets = xrealloc (r->sheets, (r->current_sheet + 1) * sizeof *r->sheets); + sd = &r->sheets[r->current_sheet]; + sd->start_col = sd->stop_col = sd->start_row = sd->stop_row = -1; + r->spreadsheet.n_sheets = r->current_sheet + 1; + } + } + else if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) && + XML_READER_TYPE_END_ELEMENT == r->node_type) + { + r->state = STATE_INIT; + r->current_sheet = -1; + } + else if (XML_READER_TYPE_TEXT == r->node_type) + { + r->sheets [r->spreadsheet.n_sheets - 1].name = xmlTextReaderValue (r->xtr); + } + break; + case STATE_INIT: if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet")) && XML_READER_TYPE_ELEMENT == r->node_type) { + ++r->current_sheet; r->state = STATE_SHEET_START; } break; @@ -225,29 +262,32 @@ process_node (struct gnumeric_reader *r) { r->state = STATE_SHEET_NAME; } - else if (0 == xmlStrcasecmp (name, _xml("gnm:Name")) && - XML_READER_TYPE_END_ELEMENT == r->node_type) - { - r->state = STATE_INIT; - } break; case STATE_SHEET_NAME: if (0 == xmlStrcasecmp (name, _xml("gnm:Name")) && XML_READER_TYPE_END_ELEMENT == r->node_type) { - r->state = STATE_SHEET_START; + r->state = STATE_INIT; + } + else if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet")) && + XML_READER_TYPE_END_ELEMENT == r->node_type) + { + r->state = STATE_INIT; } else if (XML_READER_TYPE_TEXT == r->node_type) { - ++r->sheet_index; - if ( r->target_sheet != NULL) + if ( r->target_sheet != NULL) { xmlChar *value = xmlTextReaderValue (r->xtr); if ( 0 == xmlStrcmp (value, r->target_sheet)) r->state = STATE_SHEET_FOUND; free (value); } - else if (r->target_sheet_index == r->sheet_index) + else if (r->target_sheet_index == r->current_sheet + 1) + { + r->state = STATE_SHEET_FOUND; + } + else if (r->target_sheet_index == -1) { r->state = STATE_SHEET_FOUND; } @@ -257,6 +297,7 @@ process_node (struct gnumeric_reader *r) if (0 == xmlStrcasecmp (name, _xml("gnm:Cells")) && XML_READER_TYPE_ELEMENT == r->node_type) { + r->min_col = INT_MAX; if (! xmlTextReaderIsEmptyElement (r->xtr)) r->state = STATE_CELLS_START; } @@ -265,10 +306,15 @@ process_node (struct gnumeric_reader *r) { r->state = STATE_MAXROW; } + else if (0 == xmlStrcasecmp (name, _xml("gnm:MaxCol")) && + XML_READER_TYPE_ELEMENT == r->node_type) + { + r->state = STATE_MAXCOL; + } else if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet")) && XML_READER_TYPE_END_ELEMENT == r->node_type) { - r->state = STATE_INIT; + r->state = STATE_INIT; } break; case STATE_MAXROW: @@ -277,30 +323,67 @@ process_node (struct gnumeric_reader *r) { r->state = STATE_SHEET_FOUND; } + else if (r->node_type == XML_READER_TYPE_TEXT) + { + xmlChar *value = xmlTextReaderValue (r->xtr); + r->sheets[r->current_sheet].maxrow = _xmlchar_to_int (value); + xmlFree (value); + } + break; + case STATE_MAXCOL: + if (0 == xmlStrcasecmp (name, _xml("gnm:MaxCol")) && + XML_READER_TYPE_END_ELEMENT == r->node_type) + { + r->state = STATE_SHEET_FOUND; + } + else if (r->node_type == XML_READER_TYPE_TEXT) + { + xmlChar *value = xmlTextReaderValue (r->xtr); + r->sheets[r->current_sheet].maxcol = _xmlchar_to_int (value); + xmlFree (value); + } + break; case STATE_CELLS_START: if (0 == xmlStrcasecmp (name, _xml ("gnm:Cell")) && XML_READER_TYPE_ELEMENT == r->node_type) { xmlChar *attr = NULL; - r->state = STATE_CELL; attr = xmlTextReaderGetAttribute (r->xtr, _xml ("Col")); r->col = _xmlchar_to_int (attr); free (attr); + if (r->col < r->min_col) + r->min_col = r->col; + attr = xmlTextReaderGetAttribute (r->xtr, _xml ("Row")); r->row = _xmlchar_to_int (attr); free (attr); - } - else if (0 == xmlStrcasecmp (name, _xml("gnm:Cells")) && - XML_READER_TYPE_END_ELEMENT == r->node_type) - r->state = STATE_SHEET_NAME; + if (r->sheets[r->current_sheet].start_row == -1) + { + r->sheets[r->current_sheet].start_row = r->row; + } + + if (r->sheets[r->current_sheet].start_col == -1) + { + r->sheets[r->current_sheet].start_col = r->col; + } + if (! xmlTextReaderIsEmptyElement (r->xtr)) + r->state = STATE_CELL; + } + else if ( (0 == xmlStrcasecmp (name, _xml("gnm:Cells"))) && (XML_READER_TYPE_END_ELEMENT == r->node_type) ) + { + r->sheets[r->current_sheet].stop_col = r->col; + r->sheets[r->current_sheet].stop_row = r->row; + r->state = STATE_SHEET_NAME; + } break; case STATE_CELL: - if (0 == xmlStrcasecmp (name, _xml("gnm:Cell")) && - XML_READER_TYPE_END_ELEMENT == r->node_type) - r->state = STATE_CELLS_START; + if (0 == xmlStrcasecmp (name, _xml("gnm:Cell")) && XML_READER_TYPE_END_ELEMENT == r->node_type) + { + r->state = STATE_CELLS_START; + } break; default: break; @@ -310,158 +393,165 @@ process_node (struct gnumeric_reader *r) } - /* - Change SUGGESTION until it's a valid name that can be added to DICT. -*/ + Sets the VAR of case C, to the value corresponding to the xml string XV + */ static void -devise_name (const struct dictionary *dict, struct string *name, int *x) +convert_xml_string_to_value (struct ccase *c, const struct variable *var, + const xmlChar *xv) { - struct string basename; - if ( ds_is_empty (name)) - ds_init_cstr (&basename, "var"); + union value *v = case_data_rw (c, var); + + if (xv == NULL) + value_set_missing (v, var_get_width (var)); + else if ( var_is_alpha (var)) + value_copy_str_rpad (v, var_get_width (var), xv, ' '); else - ds_init_string (&basename, name); - do { - ds_clear (name); - ds_put_format (name, "%s%d", ds_cstr (&basename), ++(*x)); - } - while (NULL != dict_lookup_var (dict, ds_cstr (name)) ); + const char *text = CHAR_CAST (const char *, xv); + char *endptr; - ds_destroy (&basename); + errno = 0; + v->f = c_strtod (text, &endptr); + if ( errno != 0 || endptr == text) + v->f = SYSMIS; + } } -/* - Mutate NAME of a variable, which is gauranteed to be valid for the - dictionary DICT. -*/ -static void -munge_name (const struct dictionary *dict, struct string *name) +struct var_spec { - int x = 0; + char *name; + int width; + xmlChar *first_value; +}; - if (! ds_is_empty (name)) - { - /* Change all the invalid characters to valid ones */ - char *s; - s = ds_data (name); +void +gnumeric_destroy (struct spreadsheet *s) +{ + gnm_file_casereader_destroy (NULL, s); +} - if ( !lex_is_id1 (*s)) - *s = '@'; - s++; +static struct gnumeric_reader * +gnumeric_reopen (struct gnumeric_reader *r, const char *filename) +{ + int ret; - while (s < ds_data (name) + ds_length (name)) - { - if ( !lex_is_idn (*s)) - *s = '_'; - s++; - } + xmlTextReaderPtr xtr; + gzFile gz; - assert (var_is_valid_name (ds_cstr (name), false)); - } + assert (r == NULL || filename == NULL); - while (ds_is_empty (name) || NULL != dict_lookup_var (dict, ds_cstr (name)) ) - { - devise_name (dict, name, &x); - } -} + if (r && r->xtr) + xmlFreeTextReader (r->xtr); + if (filename) + gz = gzopen (filename, "r"); + else + gz = gzopen ( r->spreadsheet.file_name, "r"); -/* - Sets the VAR of case C, to the value corresponding to the xml string XV - */ -static void -convert_xml_string_to_value (struct ccase *c, const struct variable *var, - const xmlChar *xv) -{ - char *text; - int n_bytes = 0; - union value *v = case_data_rw (c, var); + if (NULL == gz) + return NULL; - text = recode_string (CONV_UTF8_TO_PSPP, (const char *) xv, -1); + xtr = xmlReaderForIO ((xmlInputReadCallback) gzread, + (xmlInputCloseCallback) gzclose, gz, + NULL, NULL, 0); - if ( text) - n_bytes = MIN (var_get_width (var), strlen (text)); + if (xtr == NULL) + { + gzclose (gz); + return NULL; + } - if ( var_is_alpha (var)) + if (r == NULL) { - memcpy (v->s, text, n_bytes); + r = xzalloc (sizeof *r); + r->spreadsheet.n_sheets = -1; + r->spreadsheet.file_name = filename; } - else + + r->target_sheet = NULL; + r->target_sheet_index = -1; + + r->row = r->col = -1; + r->state = STATE_PRE_INIT; + r->xtr = xtr; + + /* Advance to the start of the workbook. + This gives us some confidence that we are actually dealing with a gnumeric + spreadsheet. + */ + while ( (r->state != STATE_INIT ) + && 1 == (ret = xmlTextReaderRead (r->xtr))) { - char *endptr; - errno = 0; - v->f = strtod (text, &endptr); - if ( errno != 0 || endptr == text) - v->f = SYSMIS; + process_node (r); } - free (text); + if ( ret != 1) + { + /* Does not seem to be a gnumeric file */ + xmlFreeTextReader (r->xtr); + free (r); + return NULL; + } + + r->spreadsheet.type = SPREADSHEET_GNUMERIC; + + return r; } -struct var_spec + +struct spreadsheet * +gnumeric_probe (const char *filename) { - char *name; - int width; - xmlChar *first_value; -}; + struct gnumeric_reader *r = gnumeric_reopen (NULL, filename); + + return &r->spreadsheet; +} + struct casereader * -gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) +gnumeric_make_reader (struct spreadsheet *spreadsheet, + const struct spreadsheet_read_info *gri, + struct spreadsheet_read_options *opts) { + struct gnumeric_reader *r = NULL; + unsigned long int vstart = 0; int ret; casenumber n_cases = CASENUMBER_MAX; int i; struct var_spec *var_spec = NULL; int n_var_specs = 0; - struct gnumeric_reader *r = NULL; + r = (struct gnumeric_reader *) (spreadsheet); - gzFile gz = gzopen (gri->file_name, "r"); + if (r->row != -1) + r = gnumeric_reopen (r, NULL); - if ( NULL == gz) + if ( opts->cell_range ) { - msg (ME, _("Error opening \"%s\" for reading as a gnumeric file: %s."), - gri->file_name, strerror (errno)); - - goto error; - } - - r = xzalloc (sizeof *r); - - r->xtr = xmlReaderForIO ((xmlInputReadCallback) gzread, gzclose, gz, - NULL, NULL, 0); - - if ( r->xtr == NULL) - goto error; - - if ( gri->cell_range ) - { - if ( ! convert_cell_ref (gri->cell_range, + if ( ! convert_cell_ref (opts->cell_range, &r->start_col, &r->start_row, &r->stop_col, &r->stop_row)) { - msg (SE, _("Invalid cell range \"%s\""), - gri->cell_range); + msg (SE, _("Invalid cell range `%s'"), + opts->cell_range); goto error; } } else { - r->start_col = 0; + r->start_col = -1; r->start_row = 0; r->stop_col = -1; r->stop_row = -1; } - r->state = STATE_INIT; - r->target_sheet = BAD_CAST gri->sheet_name; - r->target_sheet_index = gri->sheet_index; + r->target_sheet = BAD_CAST opts->sheet_name; + r->target_sheet_index = opts->sheet_index; r->row = r->col = -1; - r->sheet_index = 0; + r->current_sheet = -1; /* Advance to the start of the cells for the target sheet */ while ( (r->state != STATE_CELL || r->row < r->start_row ) @@ -478,10 +568,9 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) free (value); } - /* If a range has been given, then use that to calculate the number of cases */ - if ( gri->cell_range) + if ( opts->cell_range) { n_cases = MIN (n_cases, r->stop_row - r->start_row + 1); } @@ -512,25 +601,27 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) if ( idx >= n_var_specs ) { + int i; + var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1)); + for (i = n_var_specs; i <= idx; ++i) + { + var_spec [i].name = NULL; + var_spec [i].width = -1; + var_spec [i].first_value = NULL; + } n_var_specs = idx + 1 ; - var_spec = realloc (var_spec, sizeof (*var_spec) * n_var_specs); - var_spec [idx].name = NULL; - var_spec [idx].width = -1; - var_spec [idx].first_value = NULL; } if ( r->node_type == XML_READER_TYPE_TEXT ) { - char *text ; xmlChar *value = xmlTextReaderValue (r->xtr); - - text = recode_string (CONV_UTF8_TO_PSPP, (const char *) value, -1); + const char *text = CHAR_CAST (const char *, value); if ( r->row < r->start_row) { if ( gri->read_names ) { - var_spec [idx].name = strdup (text); + var_spec [idx].name = xstrdup (text); } } else @@ -539,11 +630,10 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) if (-1 == var_spec [idx].width ) var_spec [idx].width = (gri->asw == -1) ? - ROUND_UP (strlen(text), MAX_SHORT_STRING) : gri->asw; + ROUND_UP (strlen(text), SPREADSHEET_DEFAULT_WIDTH) : gri->asw; } free (value); - free (text); } else if ( r->node_type == XML_READER_TYPE_ELEMENT && r->state == STATE_CELL) @@ -553,7 +643,7 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) xmlChar *attr = xmlTextReaderGetAttribute (r->xtr, _xml ("ValueType")); - if ( 60 != _xmlchar_to_int (attr)) + if ( NULL == attr || 60 != _xmlchar_to_int (attr)) var_spec [idx].width = 0; free (attr); @@ -561,33 +651,29 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) } } - - /* Create the dictionary and populate it */ - *dict = r->dict = dict_create (); - - r->value_cnt = 0; + { + const xmlChar *enc = xmlTextReaderConstEncoding (r->xtr); + if ( enc == NULL) + goto error; + /* Create the dictionary and populate it */ + spreadsheet->dict = r->dict = dict_create (CHAR_CAST (const char *, enc)); + } for (i = 0 ; i < n_var_specs ; ++i ) { - struct string name; - - /* Probably no data exists for this variable, so allocate a default width */ - if ( var_spec[i].width == -1 ) - var_spec[i].width = MAX_SHORT_STRING; - - r->value_cnt += value_cnt_from_width (var_spec[i].width); - - if (var_spec[i].name) - ds_init_cstr (&name, var_spec[i].name); - else - ds_init_empty (&name); - - munge_name (r->dict, &name); + char *name; + if ( (var_spec[i].name == NULL) && (var_spec[i].first_value == NULL)) + continue; - dict_create_var (r->dict, ds_cstr (&name), var_spec[i].width); + /* Probably no data exists for this variable, so allocate a + default width */ + if ( var_spec[i].width == -1 ) + var_spec[i].width = SPREADSHEET_DEFAULT_WIDTH; - ds_destroy (&name); + name = dict_make_unique_var_name (r->dict, var_spec[i].name, &vstart); + dict_create_var (r->dict, name, var_spec[i].width); + free (name); } /* Create the first case, and cache it */ @@ -595,20 +681,24 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) if ( n_var_specs == 0 ) { - msg (MW, _("Selected sheet or range of spreadsheet \"%s\" is empty."), - gri->file_name); + msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."), + spreadsheet->file_name); goto error; } - case_create (&r->first_case, r->value_cnt); - memset (case_data_rw_idx (&r->first_case, 0)->s, - ' ', MAX_SHORT_STRING * r->value_cnt); + r->proto = caseproto_ref (dict_get_proto (r->dict)); + r->first_case = case_create (r->proto); + case_set_missing (r->first_case); + int x = 0; for ( i = 0 ; i < n_var_specs ; ++i ) { - const struct variable *var = dict_get_var (r->dict, i); + if ( (var_spec[i].name == NULL) && (var_spec[i].first_value == NULL)) + continue; - convert_xml_string_to_value (&r->first_case, var, + const struct variable *var = dict_get_var (r->dict, x++); + + convert_xml_string_to_value (r->first_case, var, var_spec[i].first_value); } @@ -619,10 +709,20 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) } free (var_spec); - + + + if (opts->cell_range == NULL) + { + opts->cell_range = c_xasprintf ("%c%d:%c%ld", + r->start_col + 'A', + r->start_row, + r->stop_col + 'A' + caseproto_get_n_widths (r->proto), + r->start_row + n_cases); + } + return casereader_create_sequential (NULL, - r->value_cnt, + r->proto, n_cases, &gnm_file_casereader_class, r); @@ -635,6 +735,8 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) } free (var_spec); + dict_destroy (spreadsheet->dict); + spreadsheet->dict = NULL; gnm_file_casereader_destroy (NULL, r); @@ -642,12 +744,12 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) }; -/* Reads one case from READER's file into C. Returns true only - if successful. */ -static bool -gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_, - struct ccase *c) +/* Reads and returns one case from READER's file. Returns a null + pointer on failure. */ +static struct ccase * +gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_) { + struct ccase *c; int ret = 0; struct gnumeric_reader *r = r_; @@ -655,14 +757,15 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_, if ( !r->used_first_case ) { - *c = r->first_case; r->used_first_case = true; - return true; + return r->first_case; } - case_create (c, r->value_cnt); + c = case_create (r->proto); + case_set_missing (c); - memset (case_data_rw_idx (c, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt); + if (r->start_col == -1) + r->start_col = r->min_col; while ((r->state == STATE_CELL || r->state == STATE_CELLS_START ) && r->row == current_row && (ret = xmlTextReaderRead (r->xtr))) @@ -673,7 +776,7 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_, r->col > r->stop_col)) continue; - if ( r->col - r->start_col >= r->value_cnt) + if ( r->col - r->start_col >= caseproto_get_n_widths (r->proto)) continue; if ( r->stop_row != -1 && r->row > r->stop_row) @@ -694,7 +797,13 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_, } - return (ret == 1); + if (ret == 1) + return c; + else + { + case_unref (c); + return NULL; + } }