Bug in Gtk+2 gtk_text_buffer_insert() of a '\n' following an existing '\r'?

2017-08-01 Thread David C. Rankin
All,

  I think I've found a bug in Gtk+2 gtk_text_buffer_insert() of a '\n'
following an existing '\r' in a GTK_TEXT_BUFFER (to convert end-of-line from
`CR` (Max pre-OSX) to `CRLF`. When I locate the existing '\r' end-of-line with
gtk_text_iter_forward_to_line_end() and gtk_text_iter_forward_char() and check
that the next char is NOT '\n', I simply want to insert a '\n' to make the
conversion. However, gtk_text_buffer_insert() inserts '\r\n' (0x0d 0x0a)
instead of '\n' making the line-end '\r\r\n'. I don't say "I think I've found
a bug" lightly, and I can already hear the "You screwed up buddy..." coming,
but bear with me.

  By simply making the change of gtk_text_buffer_backspace() to remove the
exising '\r' and then tk_text_buffer_insert() of a '\r\n' the end-of-line is
correctly converted from '\r' to '\r\n'. There is no reason I should have to
backspace over '\r' and then insert '\r\n' instead of just inserting '\n'.
Thus the bug in how gtk_text_buffer_insert() handles inserting a single '\n'
following an existing '\r'.

  This is a summary of the question (details follow afterwards)

Why does the following fail?

if (gtk_text_iter_get_char () != '\n') {
gtk_text_buffer_insert (buffer, , app->eolstr[LF], -1);
}

When the following works?

if (gtk_text_iter_get_char () != '\n') {
if (gtk_text_buffer_backspace (buffer, , FALSE, TRUE)) {
gtk_text_buffer_get_iter_at_mark (buffer, , app->last_pos);
gtk_text_buffer_insert (buffer, , app->eolstr[CRLF], -1);
}

  This is either a bug, or Gtk+2 considers CRLF a single char and will NOT
allow manual creation of '\r\n' by inseting a '\n' following an existing '\r'
in a buffer. (which Is probably where the bug (or issue) is, but I don't know
where to begin to look in the Gtk+2 source... I can remove the exising '\r'
and insert '\r\n' and everything is fine, but I cannot place a single '\n'
after an existing '\r' in the buffer and have it work.

  Here are the details for two test cases whittled down to readable examples.
First the boiler plate declarations and initialization of the EOL string and
struct values:

#define EOL_LF "\n"
#define EOL_CR "\r"
#define EOL_CRLF   "\r\n"
#define EOL_NO 3
#define EOLNM_LF   "LF"
#define EOLNM_CR   "CR"
#define EOLNM_CRLF "CRLF"

enum eolorder { LF, CRLF, CR }; /* global constants for LF, CRLF and CR */

  Declaration of struct holding values

typedef struct {
...
ginteol;/* end-of-line */
gchar   *eolnm[EOL_NO]; /* ptrs to eol names */
gchar   *eolstr[EOL_NO];/* ptrs to eol strings */
...
GtkTextMark *last_pos;  /* position of last match in buf */
...
} kwinst;

  Initializaitons of struct values passed through app (struct instance is
named 'app'):

kwinst *app = NULL; /* replaced GtkWidget *window */
app = g_slice_new (kwinst); /* allocate mem for struct*/
context_init (app); /* initialize struct values   */

  Within context_init (app), you have:

#ifndef HAVEMSWIN
app->eol= LF;   /* default line end LF */
#else
app->eol= CRLF; /* default line end CRLF */
#endif
app->eolstr[0]  = EOL_LF;   /* eol ending strings */
app->eolstr[1]  = EOL_CRLF;
app->eolstr[2]  = EOL_CR;
app->eolnm[0]   = EOLNM_LF; /* eol string names */
app->eolnm[1]   = EOLNM_CRLF;
app->eolnm[2]   = EOLNM_CR;

  The test file for the conversion loaded into buffer is a 'CR' delimited
file, e.g.

$ hexdump -C eol_cr.txt
  6d 79 0d 64 6f 67 0d 20  20 68 61 73 0d 20 20 66  |my.dog.  has.  f|
0010  6c 65 61 73 0d 61 20 6c  6f 74 0d 20 20 20 20 6f  |leas.a lot.o|
0020  66 20 66 6c 65 61 73 0d   |f fleas.|
0028

  In human readable form:

$ cat eol_cr.txt
my
dog
  has
  fleas
a lot
of fleas


  On file open 'CR' end-of-line is properly detected and app-eol is set to CR.
On menu choice the user can choose between CR, CRLF and LF line end. The
relevant parts of the function called to change from CR to CRLF that exposed
the problem is:

void buffer_convert_eol (kwinst *app)
{
GtkTextBuffer *buffer = GTK_TEXT_BUFFER(app->buffer);
GtkTextIter iter;
...
/* get iter at start of buffer */
gtk_text_buffer_get_start_iter (buffer, );

/* set app->last_pos Mark to start, and move on each iteration */
app->last_pos = gtk_text_buffer_create_mark (buffer, "last_pos", ,
FALSE);

/* loop, moving to the end of each line, before the EOL chars */
while (gtk_text_iter_forward_to_line_end ()) {

gunichar c = gtk_text_iter_get_char ();
gtk_text_buffer_move_mark (buffer, app->last_pos, );

if (c == '\n') {/* if end-of-line begins with LF */
...
}
else if (c == '\r') {   /* if end-of-line begins with CR */
  

Re: Gtk+2 Clipboard - handling EOL better on paste or copy/cut?

2017-08-01 Thread David C. Rankin
On 07/31/2017 02:05 AM, David C. Rankin wrote:
>   Does this approach sound reasonable, or like one I'll spend 1/2 day coming
> to regret?

It was... something to regret (but was solved without regret...)

  I decided to write the conversion routine first -- it answered the question.
You don't care what format the cut/copy/paste end-of-line is. You simply
handle the conversion on file-save, or run though the range of lines after
paste providing the conversion 'in-buffer' on a per-paste basis. Much simpler.


(Win32 builds need the conversion on a per-paste basis due to the way
'indention' is handled, on Linux/Unix you can just do a one-time conversion on
save)

-- 
David C. Rankin, J.D.,P.E.
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list