/** Destructor for GncCsvParseData. * @param parse_data Parse data whose memory will be freed */ void gnc_csv_parse_data_free (GncCsvParseData* parse_data) { /* All non-NULL pointers have been initialized and must be freed. */ if (parse_data->raw_mapping != NULL) { g_mapped_file_unref (parse_data->raw_mapping); } if (parse_data->file_str.begin != NULL) g_free (parse_data->file_str.begin); if (parse_data->orig_lines != NULL) stf_parse_general_free (parse_data->orig_lines); if (parse_data->orig_row_lengths != NULL) g_array_free (parse_data->orig_row_lengths, FALSE); if (parse_data->options != NULL) stf_parse_options_free (parse_data->options); if (parse_data->column_types != NULL) g_array_free (parse_data->column_types, TRUE); if (parse_data->error_lines != NULL) g_list_free (parse_data->error_lines); if (parse_data->transactions != NULL) { GList* transactions = parse_data->transactions; /* We have to free the GncCsvTransLine's that are at each node in * the list before freeing the entire list. */ do { g_free (transactions->data); transactions = g_list_next (transactions); } while (transactions != NULL); g_list_free (parse_data->transactions); } g_free (parse_data->chunk); g_free (parse_data); }
/** Parses a file into cells. This requires having an encoding that * works (see gnc_csv_convert_encoding). parse_data->options should be * set according to how the user wants before calling this * function. (Note: this function must be called with guessColTypes as * TRUE before it is ever called with it as FALSE.) (Note: if * guessColTypes is TRUE, all the column types will be GNC_CSV_NONE * right now.) * @param parse_data Data that is being parsed * @param guessColTypes TRUE to guess what the types of columns are based on the cell contents * @param error Will contain an error if there is a failure * @return 0 on success, 1 on failure */ int gnc_csv_parse (GncCsvParseData* parse_data, gboolean guessColTypes, GError** error) { /* max_cols is the number of columns in the row with the most columns. */ int i, max_cols = 0; if (parse_data->orig_lines != NULL) { stf_parse_general_free (parse_data->orig_lines); } /* If everything is fine ... */ if (parse_data->file_str.begin != NULL) { /* Do the actual parsing. */ parse_data->orig_lines = stf_parse_general (parse_data->options, parse_data->chunk, parse_data->file_str.begin, parse_data->file_str.end); } /* If we couldn't get the encoding right, we just want an empty array. */ else { parse_data->orig_lines = g_ptr_array_new(); } /* Record the original row lengths of parse_data->orig_lines. */ if (parse_data->orig_row_lengths != NULL) g_array_free (parse_data->orig_row_lengths, FALSE); parse_data->orig_row_lengths = g_array_sized_new (FALSE, FALSE, sizeof(int), parse_data->orig_lines->len); g_array_set_size (parse_data->orig_row_lengths, parse_data->orig_lines->len); parse_data->orig_max_row = 0; for (i = 0; i < parse_data->orig_lines->len; i++) { int length = ((GPtrArray*)parse_data->orig_lines->pdata[i])->len; parse_data->orig_row_lengths->data[i] = length; if (length > parse_data->orig_max_row) parse_data->orig_max_row = length; } /* If it failed, generate an error. */ if (parse_data->orig_lines == NULL) { g_set_error (error, 0, 0, "Parsing failed."); return 1; } /* Now that we have data, let's set max_cols. */ for (i = 0; i < parse_data->orig_lines->len; i++) { if (max_cols < ((GPtrArray*)(parse_data->orig_lines->pdata[i]))->len) max_cols = ((GPtrArray*)(parse_data->orig_lines->pdata[i]))->len; } if (guessColTypes) { /* Free parse_data->column_types if it's already been created. */ if (parse_data->column_types != NULL) g_array_free (parse_data->column_types, TRUE); /* Create parse_data->column_types and fill it with guesses based * on the contents of each column. */ parse_data->column_types = g_array_sized_new (FALSE, FALSE, sizeof(int), max_cols); g_array_set_size (parse_data->column_types, max_cols); /* TODO Make it actually guess. */ for (i = 0; i < parse_data->column_types->len; i++) { parse_data->column_types->data[i] = GNC_CSV_NONE; } } else { /* If we don't need to guess column types, we will simply set any * new columns that are created that didn't exist before to "None" * since we don't want gibberish to appear. Note: * parse_data->column_types should have already been * initialized, so we don't check for it being NULL. */ int i = parse_data->column_types->len; g_array_set_size (parse_data->column_types, max_cols); for (; i < parse_data->column_types->len; i++) { parse_data->column_types->data[i] = GNC_CSV_NONE; } } return 0; }
void stf_preview_set_lines (RenderData_t *renderdata, GStringChunk *lines_chunk, GPtrArray *lines) { unsigned int i; int colcount = 1; GnumericLazyList *ll; gboolean hidden; g_return_if_fail (renderdata != NULL); /* Empty the table. */ gtk_tree_view_set_model (renderdata->tree_view, NULL); if (renderdata->lines != lines) { if (renderdata->lines) stf_parse_general_free (renderdata->lines); renderdata->lines = lines; } if (renderdata->lines_chunk != lines_chunk) { if (renderdata->lines_chunk) g_string_chunk_free (renderdata->lines_chunk); renderdata->lines_chunk = lines_chunk; } if (lines == NULL) return; for (i = 0; i < lines->len; i++) { GPtrArray *line = g_ptr_array_index (lines, i); colcount = MAX (colcount, (int)line->len); } /* * If we are making large changes we need to hide the treeview * because performance otherwise suffers a lot. */ hidden = gtk_widget_get_visible (GTK_WIDGET (renderdata->tree_view)) && (colcount < renderdata->colcount - 1 || colcount > renderdata->colcount + 10); if (hidden) gtk_widget_hide (GTK_WIDGET (renderdata->tree_view)); while (renderdata->colcount > colcount) gtk_tree_view_remove_column (renderdata->tree_view, gtk_tree_view_get_column (renderdata->tree_view, --(renderdata->colcount))); while (renderdata->colcount < colcount) { char *text = g_strdup_printf (_(COLUMN_CAPTION), renderdata->colcount + 1); GtkCellRenderer *cell = gtk_cell_renderer_text_new (); GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes (text, cell, "text", renderdata->colcount, NULL); g_object_set (cell, "single_paragraph_mode", TRUE, NULL); gtk_tree_view_append_column (renderdata->tree_view, column); g_free (text); renderdata->colcount++; } ll = gnumeric_lazy_list_new (render_get_value, renderdata, MIN (lines->len, LINE_DISPLAY_LIMIT), 0); gnumeric_lazy_list_add_column (ll, colcount, G_TYPE_STRING); gtk_tree_view_set_model (renderdata->tree_view, GTK_TREE_MODEL (ll)); g_object_unref (ll); if (hidden) gtk_widget_show (GTK_WIDGET (renderdata->tree_view)); }
/* * stf_read_workbook_auto_csvtab: * @fo: file opener * @enc: optional encoding * @context: command context * @book: workbook * @input: file to read from+convert * * Attempt to auto-detect CSV or tab-delimited file */ static void stf_read_workbook_auto_csvtab (G_GNUC_UNUSED GOFileOpener const *fo, gchar const *enc, GOIOContext *context, GoView *view, GsfInput *input) { Sheet *sheet; Workbook *book; char *name; char *data; GString *utf8data; size_t data_len; StfParseOptions_t *po; const char *gsfname; int cols, rows, i; GStringChunk *lines_chunk; GPtrArray *lines; WorkbookView *wbv = GNM_WORKBOOK_VIEW (view); g_return_if_fail (context != NULL); g_return_if_fail (wbv != NULL); book = wb_view_get_workbook (wbv); data = stf_preparse (context, input, &data_len); if (!data) return; enc = go_guess_encoding (data, data_len, enc, &utf8data, NULL); g_free (data); if (!enc) { go_cmd_context_error_import (GO_CMD_CONTEXT (context), _("That file is not in the given encoding.")); return; } clear_stray_NULs (context, utf8data); /* * Try to get the filename we're reading from. This is not a * great way. */ gsfname = gsf_input_name (input); { const char *ext = gsf_extension_pointer (gsfname); gboolean iscsv = ext && strcasecmp (ext, "csv") == 0; if (iscsv) po = stf_parse_options_guess_csv (utf8data->str); else po = stf_parse_options_guess (utf8data->str); } lines_chunk = g_string_chunk_new (100 * 1024); lines = stf_parse_general (po, lines_chunk, utf8data->str, utf8data->str + utf8data->len); rows = lines->len; cols = 0; for (i = 0; i < rows; i++) { GPtrArray *line = g_ptr_array_index (lines, i); cols = MAX (cols, (int)line->len); } gnm_sheet_suggest_size (&cols, &rows); stf_parse_general_free (lines); g_string_chunk_free (lines_chunk); name = g_path_get_basename (gsfname); sheet = sheet_new (book, name, cols, rows); g_free (name); workbook_sheet_attach (book, sheet); if (stf_parse_sheet (po, utf8data->str, NULL, sheet, 0, 0)) { gboolean is_csv; workbook_recalc_all (book); resize_columns (sheet); if (po->cols_exceeded || po->rows_exceeded) { stf_warning (context, _("Some data did not fit on the " "sheet and was dropped.")); } is_csv = po->sep.chr && po->sep.chr[0] == ','; workbook_set_saveinfo (book, GO_FILE_FL_WRITE_ONLY, go_file_saver_for_id (is_csv ? "Gnumeric_stf:stf_csv" : "Gnumeric_stf:stf_assistant")); } else { workbook_sheet_delete (sheet); go_cmd_context_error_import (GO_CMD_CONTEXT (context), _("Parse error while trying to parse data into sheet")); } stf_parse_options_free (po); g_string_free (utf8data, TRUE); }