442
gchar *data; // null-terminated file data
443
gsize len; // string length of data
446
time_t mtime; // modification time, read by stat::st_mtime
424
451
// reload file with specified encoding
426
handle_forced_encoding(gchar **data, gsize *size, const gchar *forced_enc, gchar **enc,
453
handle_forced_encoding(FileData *filedata, const gchar *forced_enc)
455
GeanyEncodingIndex enc_idx;
429
457
if (utils_str_equal(forced_enc, "UTF-8"))
431
if (! g_utf8_validate(*data, *size, NULL))
459
if (! g_utf8_validate(filedata->data, filedata->len, NULL))
437
*bom = utils_str_equal(utils_scan_unicode_bom(*data), "UTF-8");
438
*enc = g_strdup(forced_enc);
443
466
gchar *converted_text = encodings_convert_to_utf8_from_charset(
444
*data, *size, forced_enc, FALSE);
467
filedata->data, filedata->len, forced_enc, FALSE);
445
468
if (converted_text == NULL)
452
*data = (void*)converted_text;
453
*size = strlen(converted_text);
454
*bom = utils_str_equal(utils_scan_unicode_bom(*data), "UTF-8");
455
*enc = g_strdup(forced_enc);
474
g_free(filedata->data);
475
filedata->data = converted_text;
476
filedata->len = strlen(converted_text);
479
enc_idx = encodings_scan_unicode_bom(filedata->data, filedata->len, NULL);
480
filedata->bom = (enc_idx == GEANY_ENCODING_UTF_8);
481
filedata->enc = g_strdup(forced_enc);
486
// detect encoding and convert to UTF-8 if necessary
463
handle_encoding(gchar **data, gsize *size, gchar **enc, gboolean *bom)
488
handle_encoding(FileData *filedata)
466
{ // the usual way to detect encoding and convert to UTF-8
469
*enc = utils_scan_unicode_bom(*data);
474
if ((*enc)[4] != '8') // the BOM indicated something else than UTF-8
490
g_return_val_if_fail(filedata->enc == NULL, FALSE);
491
g_return_val_if_fail(filedata->bom == FALSE, FALSE);
493
if (filedata->len == 0)
495
// we have no data so assume UTF-8
496
filedata->enc = g_strdup("UTF-8");
500
// first check for a BOM
501
GeanyEncodingIndex enc_idx =
502
encodings_scan_unicode_bom(filedata->data, filedata->len, NULL);
504
if (enc_idx != GEANY_ENCODING_NONE)
506
filedata->enc = g_strdup(encodings[enc_idx].charset);
507
filedata->bom = TRUE;
509
if (enc_idx != GEANY_ENCODING_UTF_8) // the BOM indicated something else than UTF-8
476
511
gchar *converted_text = encodings_convert_to_utf8_from_charset(
477
*data, *size, *enc, FALSE);
478
if (converted_text == NULL)
512
filedata->data, filedata->len, filedata->enc, FALSE);
513
if (converted_text != NULL)
515
g_free(filedata->data);
516
filedata->data = converted_text;
517
filedata->len = strlen(converted_text);
487
*data = (void*)converted_text;
488
*size = strlen(converted_text);
521
// there was a problem converting data from BOM encoding type
522
g_free(filedata->enc);
523
filedata->enc = NULL;
524
filedata->bom = FALSE;
492
// this if is important, else doesn't work because enc can be altered in the above block
529
if (filedata->enc == NULL) // either there was no BOM or the BOM encoding failed
495
if (g_utf8_validate(*data, *size, NULL))
532
if (g_utf8_validate(filedata->data, filedata->len, NULL))
497
*enc = g_strdup("UTF-8");
534
filedata->enc = g_strdup("UTF-8");
501
gchar *converted_text = encodings_convert_to_utf8(*data, *size, enc);
538
// detect the encoding
539
gchar *converted_text = encodings_convert_to_utf8(filedata->data,
540
filedata->len, &filedata->enc);
503
542
if (converted_text == NULL)
510
*data = (void*)converted_text;
511
*size = strlen(converted_text);
546
g_free(filedata->data);
547
filedata->data = converted_text;
548
filedata->len = strlen(converted_text);
518
*enc = g_strdup("UTF-8");
525
handle_bom(gchar **data)
527
gchar *data_without_bom;
528
data_without_bom = g_strdup(*data + 3);
530
*data = data_without_bom;
557
handle_bom(FileData *filedata)
561
encodings_scan_unicode_bom(filedata->data, filedata->len, &bom_len);
562
g_return_if_fail(bom_len != 0);
564
filedata->len -= bom_len;
565
// overwrite the BOM with the remainder of the file contents, plus the NULL terminator.
566
g_memmove(filedata->data, filedata->data + bom_len, filedata->len + 1);
567
filedata->data = g_realloc(filedata->data, filedata->len + 1);
571
/* loads textfile data, verifies and converts to forced_enc or UTF-8. Also handles BOM. */
572
static gboolean load_text_file(const gchar *locale_filename, const gchar *utf8_filename,
573
FileData *filedata, const gchar *forced_enc)
578
filedata->data = NULL;
580
filedata->enc = NULL;
581
filedata->bom = FALSE;
582
filedata->readonly = FALSE;
584
if (stat(locale_filename, &st) != 0)
586
msgwin_status_add(_("Could not open file %s (%s)"), utf8_filename, g_strerror(errno));
590
filedata->mtime = st.st_mtime;
593
if (! g_file_get_contents(utf8_filename, &filedata->data, NULL, &err))
595
if (! g_file_get_contents(locale_filename, &filedata->data, NULL, &err))
598
msgwin_status_add(err->message);
603
// use strlen to check for null chars
604
filedata->len = strlen(filedata->data);
606
/* check whether the size of the loaded data is equal to the size of the file in the filesystem */
607
if (filedata->len != (gsize) st.st_size)
609
gchar *warn_msg = _("The file \"%s\" could not be opened properly and has been truncated. "
610
"This can occur if the file contains a NULL byte. "
611
"Be aware that saving it can cause data loss.\nThe file was set to read-only.");
613
if (app->main_window_realized)
614
dialogs_show_msgbox(GTK_MESSAGE_WARNING, warn_msg, utf8_filename);
616
msgwin_status_add(warn_msg, utf8_filename);
618
// set the file to read-only mode because saving it is probably dangerous
619
filedata->readonly = TRUE;
622
/* Determine character encoding and convert to UTF-8 */
623
if (forced_enc != NULL)
625
// the encoding should be ignored(requested by user), so open the file "as it is"
626
if (utils_str_equal(forced_enc, encodings[GEANY_ENCODING_NONE].charset))
628
filedata->bom = FALSE;
629
filedata->enc = g_strdup(encodings[GEANY_ENCODING_NONE].charset);
631
else if (! handle_forced_encoding(filedata, forced_enc))
633
msgwin_status_add(_("The file \"%s\" is not valid %s."), utf8_filename, forced_enc);
635
g_free(filedata->data);
639
else if (! handle_encoding(filedata))
642
_("The file \"%s\" does not look like a text file or the file encoding is not supported."),
645
g_free(filedata->data);
650
handle_bom(filedata);
655
/* Sets the cursor position on opening a file. First it sets the line when cl_options.goto_line
656
* is set, otherwise it sets the line when pos is greater than zero. */
657
static void set_cursor_position(gint idx, gint pos)
659
if (cl_options.goto_line >= 0)
660
{ // goto line which was specified on command line and then undefine the line
661
sci_goto_line(doc_list[idx].sci, cl_options.goto_line - 1, TRUE);
662
doc_list[idx].scroll_percent = 0.5F;
663
cl_options.goto_line = -1;
667
sci_set_current_position(doc_list[idx].sci, pos, FALSE);
668
doc_list[idx].scroll_percent = 0.5F;
585
719
g_free(utf8_filename);
586
720
g_free(locale_filename);
587
721
utils_check_disk_status(idx, TRUE); // force a file changed check
722
set_cursor_position(idx, pos);
592
if (stat(locale_filename, &st) != 0)
594
msgwin_status_add(_("Could not open file %s (%s)"), utf8_filename, g_strerror(errno));
595
g_free(utf8_filename);
596
g_free(locale_filename);
601
if (! g_file_get_contents(utf8_filename, &data, NULL, &err))
603
if (! g_file_get_contents(locale_filename, &data, NULL, &err))
606
msgwin_status_add(err->message);
608
g_free(utf8_filename);
609
g_free(locale_filename);
613
/* check whether the size of the loaded data is equal to the size of the file in the filesystem */
614
//size = strlen(data);
616
if (size != (gsize) st.st_size)
618
gchar *warn_msg = _("The file \"%s\" could not opened properly and probably was truncated. "
619
"Be aware that saving it can cause data loss.\nThe file was set to read-only.");
621
if (app->main_window_realized)
622
dialogs_show_msgbox(GTK_MESSAGE_WARNING, warn_msg, utf8_filename);
624
msgwin_status_add(warn_msg, utf8_filename);
626
// set the file to read-only mode because saving it is probably dangerous
630
/* Determine character encoding and convert to UTF-8 */
631
if (forced_enc != NULL)
633
// the encoding should be ignored(requested by user), so open the file "as it is"
634
if (utils_str_equal(forced_enc, encodings[GEANY_ENCODING_NONE].charset))
637
enc = g_strdup(encodings[GEANY_ENCODING_NONE].charset);
639
else if (! handle_forced_encoding(&data, &size, forced_enc, &enc, &bom))
641
msgwin_status_add(_("The file \"%s\" is not valid %s."), utf8_filename, forced_enc);
644
g_free(utf8_filename);
645
g_free(locale_filename);
649
else if (! handle_encoding(&data, &size, &enc, &bom))
652
_("The file \"%s\" does not look like a text file or the file encoding is not supported."),
656
g_free(utf8_filename);
657
g_free(locale_filename);
661
if (bom) handle_bom(&data);
727
if (! load_text_file(locale_filename, utf8_filename, &filedata, forced_enc))
729
g_free(utf8_filename);
730
g_free(locale_filename);
663
734
if (! reload) idx = document_create_new_sci(utf8_filename);
664
if (idx == -1) return -1; // really should not happen
735
g_return_val_if_fail(idx != -1, -1); // really should not happen
666
// set editor mode and add the text to the ScintillaObject
667
737
sci_set_undo_collection(doc_list[idx].sci, FALSE); // avoid creation of an undo action
668
738
sci_empty_undo_buffer(doc_list[idx].sci);
669
sci_set_text(doc_list[idx].sci, data); // NULL terminated data
671
editor_mode = utils_get_line_endings(data, size);
740
// add the text to the ScintillaObject
741
sci_set_text(doc_list[idx].sci, filedata.data); // NULL terminated data
743
// detect & set line endings
744
editor_mode = utils_get_line_endings(filedata.data, filedata.len);
672
745
sci_set_eol_mode(doc_list[idx].sci, editor_mode);
673
sci_set_line_numbers(doc_list[idx].sci, app->show_linenumber_margin, 0);
746
g_free(filedata.data);
675
748
sci_set_undo_collection(doc_list[idx].sci, TRUE);
677
doc_list[idx].mtime = st.st_mtime; // get the modification time from file and keep it
750
doc_list[idx].mtime = filedata.mtime; // get the modification time from file and keep it
678
751
doc_list[idx].changed = FALSE;
679
752
g_free(doc_list[idx].encoding); // if reloading, free old encoding
680
doc_list[idx].encoding = enc;
681
doc_list[idx].has_bom = bom;
753
doc_list[idx].encoding = filedata.enc;
754
doc_list[idx].has_bom = filedata.bom;
682
755
store_saved_encoding(idx); // store the opened encoding for undo/redo
684
if (cl_options.goto_line >= 0)
685
{ // goto line which was specified on command line and then undefine the line
686
sci_goto_line(doc_list[idx].sci, cl_options.goto_line - 1, TRUE);
687
sci_scroll_to_line(doc_list[idx].sci, -1, 0.5);
688
cl_options.goto_line = -1;
692
sci_goto_pos(doc_list[idx].sci, pos, FALSE);
694
sci_scroll_to_line(doc_list[idx].sci, -1, 0.5);
757
doc_list[idx].readonly = readonly || filedata.readonly;
758
sci_set_readonly(doc_list[idx].sci, doc_list[idx].readonly);
760
// update line number margin width
761
sci_set_line_numbers(doc_list[idx].sci, app->show_linenumber_margin, 0);
763
// set the cursor position according to pos, cl_options.goto_line and cl_options.goto_column
764
set_cursor_position(idx, pos);
699
doc_list[idx].readonly = readonly;
700
sci_set_readonly(doc_list[idx].sci, readonly);
702
768
// "the" SCI signal (connect after initial setup(i.e. adding text))
703
769
g_signal_connect((GtkWidget*) doc_list[idx].sci, "sci-notify",
704
770
G_CALLBACK(on_editor_notification), GINT_TO_POINTER(idx));