#include "spreadsheet-reader.h"
+#include "c-xvasprintf.h"
+
#if !GNM_SUPPORT
struct casereader *
-gnumeric_open_reader (struct spreadsheet_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 %s files was not compiled into this installation of PSPP"), "Gnumeric");
};
struct casereader *
-gnumeric_open_reader (struct spreadsheet_read_info *gri, struct dictionary **dict)
+gnumeric_open_reader (const struct spreadsheet_read_info *gri,
+ struct spreadsheet_read_options *opts,
+ struct dictionary **dict)
{
unsigned long int vstart = 0;
int ret;
if ( r->xtr == NULL )
goto error;
- if ( gri->cell_range )
+ if ( opts->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);
+ opts->cell_range);
goto error;
}
}
}
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;
/* 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);
}
}
free (var_spec);
-
+
+
+ if (opts->cell_range == NULL)
+ {
+ opts->cell_range = c_xasprintf ("%c%d:%c%d",
+ 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->proto,
struct casereader;
struct dictionary;
struct spreadsheet_read_info;
+struct spreadsheet_read_options;
-struct casereader * gnumeric_open_reader (struct spreadsheet_read_info *, struct dictionary **);
+struct casereader * gnumeric_open_reader (const struct spreadsheet_read_info *,
+ struct spreadsheet_read_options *,
+ struct dictionary **);
#endif
#if !ODF_READ_SUPPORT
struct casereader *
-ods_open_reader (struct spreadsheet_read_info *gri, struct dictionary **dict)
+ods_open_reader (const struct spreadsheet_read_info *gri, struct spreadsheet_read_options *opts,
+ struct dictionary **dict)
{
msg (ME, _("Support for %s files was not compiled into this installation of PSPP"), "OpenDocument");
struct casereader *
-ods_open_reader (struct spreadsheet_read_info *gri, struct dictionary **dict)
+ods_open_reader (const struct spreadsheet_read_info *gri, struct spreadsheet_read_options *opts,
+ struct dictionary **dict)
{
int ret = 0;
xmlChar *type = NULL;
goto error;
}
- if ( gri->cell_range )
+ if ( opts->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);
+ opts->cell_range);
goto error;
}
}
}
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;
struct casereader;
struct dictionary;
struct spreadsheet_read_info;
+struct spreadsheet_read_options;
-struct casereader * ods_open_reader (struct spreadsheet_read_info *, struct dictionary **);
+
+struct casereader * ods_open_reader (const struct spreadsheet_read_info *,
+ struct spreadsheet_read_options *,
+ struct dictionary **);
#endif
/* Default width of string variables. */
#define SPREADSHEET_DEFAULT_WIDTH 8
+/* These elements are read/write.
+ They may be passed in NULL (for pointers) or negative for integers, in which
+ case they will be filled in be the function.
+*/
+struct spreadsheet_read_options
+{
+ char *sheet_name ; /* The name of the sheet to open (in UTF-8) */
+ int sheet_index ; /* The index of the sheet to open (only used if sheet_name is NULL) */
+ char *cell_range ; /* The cell range (in UTF-8) */
+};
+
+
struct spreadsheet_read_info
{
- char *sheet_name ; /* In UTF-8. */
- char *file_name ; /* In filename encoding. */
- char *cell_range ; /* In UTF-8. */
- int sheet_index ;
- bool read_names ;
- int asw ;
+ char *file_name ; /* The name of the file to open (in filename encoding) */
+ bool read_names ; /* True if the first row is to be used as the names of the variables */
+ int asw ; /* The width of string variables in the created dictionary */
};
int pseudo_base26 (const char *str);
#define _(msgid) gettext (msgid)
#define N_(msgid) (msgid)
-static struct spreadsheet_read_info *parse_spreadsheet (struct lexer *lexer);
-static void destroy_spreadsheet_read_info (struct spreadsheet_read_info *);
+static bool parse_spreadsheet (struct lexer *lexer, struct spreadsheet_read_info *sri,
+ struct spreadsheet_read_options *opts);
+
+static void destroy_spreadsheet_read_info (struct spreadsheet_read_info *, struct spreadsheet_read_options *);
static int parse_get_txt (struct lexer *lexer, struct dataset *);
static int parse_get_psql (struct lexer *lexer, struct dataset *);
{
struct casereader *reader = NULL;
struct dictionary *dict = NULL;
- struct spreadsheet_read_info *sri = parse_spreadsheet (lexer);
- if (NULL == sri)
+ struct spreadsheet_read_info sri;
+ struct spreadsheet_read_options opts;
+ if (!parse_spreadsheet (lexer, &sri, &opts))
goto error;
if ( 0 == strncasecmp (tok, "GNM", 3))
- reader = gnumeric_open_reader (sri, &dict);
+ reader = gnumeric_open_reader (&sri, &opts, &dict);
else if (0 == strncasecmp (tok, "ODS", 3))
- reader = ods_open_reader (sri, &dict);
+ reader = ods_open_reader (&sri, &opts, &dict);
if (reader)
{
dataset_set_dict (ds, dict);
dataset_set_source (ds, reader);
- destroy_spreadsheet_read_info (sri);
+ destroy_spreadsheet_read_info (&sri, &opts);
free (tok);
return CMD_SUCCESS;
}
- destroy_spreadsheet_read_info (sri);
+ destroy_spreadsheet_read_info (&sri, &opts);
}
else
msg (SE, _("Unsupported TYPE %s."), tok);
return CMD_FAILURE;
}
-static struct spreadsheet_read_info *
-parse_spreadsheet (struct lexer *lexer)
+static bool
+parse_spreadsheet (struct lexer *lexer, struct spreadsheet_read_info *sri,
+ struct spreadsheet_read_options *opts)
{
- struct spreadsheet_read_info *sri = xzalloc (sizeof *sri);
- sri->sheet_index = 1;
+ opts->sheet_index = 1;
+ opts->sheet_name = NULL;
+ opts->cell_range = NULL;
sri->read_names = true;
sri->asw = -1;
+ sri->file_name = NULL;
lex_force_match (lexer, T_SLASH);
if ( ! lex_force_string (lexer) )
goto error;
- sri->sheet_name = ss_xstrdup (lex_tokss (lexer));
- sri->sheet_index = -1;
+ opts->sheet_name = ss_xstrdup (lex_tokss (lexer));
+ opts->sheet_index = -1;
lex_get (lexer);
}
if (lex_match_id (lexer, "FULL"))
{
- sri->cell_range = NULL;
+ opts->cell_range = NULL;
}
else if (lex_match_id (lexer, "RANGE"))
{
if ( ! lex_force_string (lexer) )
goto error;
- sri->cell_range = ss_xstrdup (lex_tokss (lexer));
+ opts->cell_range = ss_xstrdup (lex_tokss (lexer));
lex_get (lexer);
}
else
}
}
- return sri;
+ return true;
error:
- destroy_spreadsheet_read_info (sri);
- return NULL;
+ destroy_spreadsheet_read_info (sri, opts);
+ return false;
}
static void
-destroy_spreadsheet_read_info (struct spreadsheet_read_info *sri)
+destroy_spreadsheet_read_info (struct spreadsheet_read_info *sri,
+ struct spreadsheet_read_options *opts)
{
- if ( NULL == sri)
- return;
-
- free (sri->sheet_name);
- free (sri->cell_range);
+ free (opts->sheet_name);
+ free (opts->cell_range);
free (sri->file_name);
- free (sri);
}
#include "data/data-in.h"
#include "data/data-out.h"
#include "data/format-guesser.h"
+#include "data/casereader.h"
#include "data/gnumeric-reader.h"
+#include "data/ods-reader.h"
#include "data/spreadsheet-reader.h"
#include "data/value-labels.h"
#include "language/data-io/data-parser.h"
bool
init_file (struct import_assistant *ia, GtkWindow *parent_window)
{
+ enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
+ enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
struct file *file = &ia->file;
+ struct separators_page *sepp = &ia->separators;
+ struct casereader *creader = NULL;
+ struct dictionary *dict = NULL;
+ struct spreadsheet_read_info sri;
+ struct spreadsheet_read_options opts;
+
+ file->lines = NULL;
file->file_name = choose_file (parent_window, &file->encoding);
if (file->file_name == NULL)
return false;
- struct dictionary *dict = NULL;
- struct spreadsheet_read_info sri;
+ opts.sheet_name = NULL;
+ opts.cell_range = NULL;
+ opts.sheet_index = 1;
- sri.sheet_name = NULL;
sri.file_name = file->file_name;
- sri.cell_range = NULL;
- sri.sheet_index = 1;
sri.read_names = true;
- sri.asw = 0;
+ sri.asw = -1;
- struct casereader *creader = gnumeric_open_reader (&sri, &dict);
- printf ("%s:%d %s\n", __FILE__, __LINE__, sri.file_name);
- ia->file.type = FTYPE_SPREADSHEET;
-
- if (creader == NULL)
- {
- enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
- enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
+ if (!creader)
+ {
+ creader = gnumeric_open_reader (&sri, &opts, &dict);
+ ia->file.type = FTYPE_GNUMERIC;
+ }
+
+ if (!creader)
+ {
+ creader = ods_open_reader (&sri, &opts, &dict);
+ ia->file.type = FTYPE_ODS;
+ }
+
+ if (creader)
+ {
+ int col;
+ int rows = 0;
+ struct ccase *c;
+
+ sepp->column_cnt = dict_get_var_cnt (dict);
+ sepp->columns = xcalloc (sepp->column_cnt, sizeof (*sepp->columns));
+ for (col = 0; col < sepp->column_cnt ; ++col)
+ {
+ const struct variable *var = dict_get_var (dict, col);
+ sepp->columns[col].name = xstrdup (var_get_name (var));
+ sepp->columns[col].contents = NULL;
+ }
+
+ for (; (c = casereader_read (creader)) != NULL; case_unref (c))
+ {
+ rows++;
+ for (col = 0; col < sepp->column_cnt ; ++col)
+ {
+ char *ss;
+ const struct variable *var = dict_get_var (dict, col);
+
+ sepp->columns[col].contents = xrealloc (sepp->columns[col].contents,
+ sizeof (struct substring) * rows);
+
+ ss = data_out (case_data (c, var), dict_get_encoding (dict),
+ var_get_print_format (var));
+
+ sepp->columns[col].contents[rows - 1] = ss_cstr (ss);
+ }
+
+ if (rows > MAX_PREVIEW_LINES)
+ {
+ case_unref (c);
+ break;
+ }
+ }
+ file->line_cnt = rows;
+ casereader_destroy (creader);
+ }
+ else
+ {
struct string input;
struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
if (reader == NULL)
struct file *f = &ia->file;
size_t i;
- for (i = 0; i < f->line_cnt; i++)
- ds_destroy (&f->lines[i]);
- free (f->lines);
+ if (f->lines)
+ {
+ for (i = 0; i < f->line_cnt; i++)
+ ds_destroy (&f->lines[i]);
+ free (f->lines);
+ }
+
g_free (f->file_name);
g_free (f->encoding);
}
static void add_line_number_column (const struct import_assistant *,
GtkTreeView *);
+
/* Pops up the Text Data Import assistant. */
void
text_data_import_assistant (PsppireDataWindow *dw)
{
struct string s = DS_EMPTY_INITIALIZER;
- if (ia->file.type == FTYPE_TEXT)
- {
- size_t var_cnt;
- size_t i;
- syntax_gen_pspp (&s,
- "GET DATA\n"
- " /TYPE=TXT\n"
- " /FILE=%sq\n",
- ia->file.file_name);
- if (ia->file.encoding && strcmp (ia->file.encoding, "Auto"))
- syntax_gen_pspp (&s, " /ENCODING=%sq\n", ia->file.encoding);
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
- ia->intro.n_cases_button)))
- ds_put_format (&s, " /IMPORTCASES=FIRST %d\n",
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (ia->intro.n_cases_spin)));
- else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
- ia->intro.percent_button)))
- ds_put_format (&s, " /IMPORTCASES=PERCENT %d\n",
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (ia->intro.percent_spin)));
- else
- ds_put_cstr (&s, " /IMPORTCASES=ALL\n");
- ds_put_cstr (&s,
- " /ARRANGEMENT=DELIMITED\n"
- " /DELCASE=LINE\n");
- if (ia->first_line.skip_lines > 0)
- ds_put_format (&s, " /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1);
- ds_put_cstr (&s, " /DELIMITERS=\"");
- if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX)
- ds_put_cstr (&s, "\\t");
- if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX)
- ds_put_cstr (&s, "\\\\");
- for (i = 0; i < ds_length (&ia->separators.separators); i++)
+ switch (ia->file.type)
+ {
+ case FTYPE_TEXT:
{
- char c = ds_at (&ia->separators.separators, i);
- if (c == '"')
- ds_put_cstr (&s, "\"\"");
- else if (c != '\t' && c != '\\')
- ds_put_byte (&s, c);
+ size_t var_cnt;
+ size_t i;
+ syntax_gen_pspp (&s,
+ "GET DATA\n"
+ " /TYPE=TXT\n"
+ " /FILE=%sq\n",
+ ia->file.file_name);
+ if (ia->file.encoding && strcmp (ia->file.encoding, "Auto"))
+ syntax_gen_pspp (&s, " /ENCODING=%sq\n", ia->file.encoding);
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
+ ia->intro.n_cases_button)))
+ ds_put_format (&s, " /IMPORTCASES=FIRST %d\n",
+ gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (ia->intro.n_cases_spin)));
+ else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
+ ia->intro.percent_button)))
+ ds_put_format (&s, " /IMPORTCASES=PERCENT %d\n",
+ gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (ia->intro.percent_spin)));
+ else
+ ds_put_cstr (&s, " /IMPORTCASES=ALL\n");
+ ds_put_cstr (&s,
+ " /ARRANGEMENT=DELIMITED\n"
+ " /DELCASE=LINE\n");
+ if (ia->first_line.skip_lines > 0)
+ ds_put_format (&s, " /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1);
+ ds_put_cstr (&s, " /DELIMITERS=\"");
+ if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX)
+ ds_put_cstr (&s, "\\t");
+ if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX)
+ ds_put_cstr (&s, "\\\\");
+ for (i = 0; i < ds_length (&ia->separators.separators); i++)
+ {
+ char c = ds_at (&ia->separators.separators, i);
+ if (c == '"')
+ ds_put_cstr (&s, "\"\"");
+ else if (c != '\t' && c != '\\')
+ ds_put_byte (&s, c);
+ }
+ ds_put_cstr (&s, "\"\n");
+ if (!ds_is_empty (&ia->separators.quotes))
+ syntax_gen_pspp (&s, " /QUALIFIER=%sq\n", ds_cstr (&ia->separators.quotes));
+ if (!ds_is_empty (&ia->separators.quotes) && ia->separators.escape)
+ ds_put_cstr (&s, " /ESCAPE\n");
+ ds_put_cstr (&s, " /VARIABLES=\n");
+
+ var_cnt = dict_get_var_cnt (ia->formats.dict);
+ for (i = 0; i < var_cnt; i++)
+ {
+ struct variable *var = dict_get_var (ia->formats.dict, i);
+ char format_string[FMT_STRING_LEN_MAX + 1];
+ fmt_to_string (var_get_print_format (var), format_string);
+ ds_put_format (&s, " %s %s%s\n",
+ var_get_name (var), format_string,
+ i == var_cnt - 1 ? "." : "");
+ }
+
+ apply_dict (ia->formats.dict, &s);
}
- ds_put_cstr (&s, "\"\n");
- if (!ds_is_empty (&ia->separators.quotes))
- syntax_gen_pspp (&s, " /QUALIFIER=%sq\n", ds_cstr (&ia->separators.quotes));
- if (!ds_is_empty (&ia->separators.quotes) && ia->separators.escape)
- ds_put_cstr (&s, " /ESCAPE\n");
- ds_put_cstr (&s, " /VARIABLES=\n");
-
- var_cnt = dict_get_var_cnt (ia->formats.dict);
- for (i = 0; i < var_cnt; i++)
+ break;
+ case FTYPE_GNUMERIC:
{
- struct variable *var = dict_get_var (ia->formats.dict, i);
- char format_string[FMT_STRING_LEN_MAX + 1];
- fmt_to_string (var_get_print_format (var), format_string);
- ds_put_format (&s, " %s %s%s\n",
- var_get_name (var), format_string,
- i == var_cnt - 1 ? "." : "");
+ syntax_gen_pspp (&s,
+ "GET DATA\n"
+ " /TYPE=GNM\n"
+ " /FILE=%sq\n",
+ ia->file.file_name);
}
+ break;
+
+ case FTYPE_ODS:
+ {
+ syntax_gen_pspp (&s,
+ "GET DATA\n"
+ " /TYPE=ODS\n"
+ " /FILE=%sq\n",
+ ia->file.file_name);
+ }
+ break;
- apply_dict (ia->formats.dict, &s);
- }
- else
- {
- syntax_gen_pspp (&s,
- "GET DATA\n"
- " /TYPE=GNM\n"
- " /FILE=%sq\n",
- ia->file.file_name);
+
+ default:
+ g_assert_not_reached ();
}
preview tree view. */
static gboolean
on_query_output_tooltip (GtkWidget *widget, gint wx, gint wy,
- gboolean keyboard_mode UNUSED,
- GtkTooltip *tooltip, struct import_assistant *ia)
+ gboolean keyboard_mode UNUSED,
+ GtkTooltip *tooltip, struct import_assistant *ia)
{
size_t row, column;
char *text;
*tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
model = GTK_TREE_MODEL (psppire_empty_list_store_new (
- ia->file.line_cnt - first_line));
+ ia->file.line_cnt - first_line));
g_object_set_data (G_OBJECT (model), "lines", ia->file.lines + first_line);
g_object_set_data (G_OBJECT (model), "first-line",
GINT_TO_POINTER (first_line));
GtkTreeViewColumn *column;
column = gtk_tree_view_column_new_with_attributes (
- _("Line"), ia->asst.prop_renderer, (void *) NULL);
+ _("Line"), ia->asst.prop_renderer, (void *) NULL);
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width (
- column, get_monospace_width (treeview, ia->asst.prop_renderer, 5));
+ column, get_monospace_width (treeview, ia->asst.prop_renderer, 5));
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_column_set_cell_data_func (column, ia->asst.prop_renderer,
render_line_number, NULL, NULL);
gtk_tree_view_column_pack_start (tree_column, ia->asst.fixed_renderer,
FALSE);
gtk_tree_view_column_set_cell_data_func (
- tree_column, ia->asst.fixed_renderer,
- input ? render_input_cell : render_output_cell, ia, NULL);
+ tree_column, ia->asst.fixed_renderer,
+ input ? render_input_cell : render_output_cell, ia, NULL);
gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width,
header_width));
enum file_type
{
FTYPE_TEXT,
- FTYPE_SPREADSHEET
+ FTYPE_GNUMERIC,
+ FTYPE_ODS
};
/* The file to be imported. */
void init_intro_page (struct import_assistant *);
void reset_intro_page (struct import_assistant *);
+void init_sheet_spec_page (struct import_assistant *);
+void reset_sheet_spec_page (struct import_assistant *);
+
void init_first_line_page (struct import_assistant *ia);
void prepare_first_line_page (struct import_assistant *ia);
void reset_first_line_page (struct import_assistant *);