/* PSPP - a program for statistical analysis.
Copyright (C) 2011 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
/* A lex_reader object to read characters directly from a GtkTextBuffer */
#include
#include "psppire-lex-reader.h"
#include "src/language/lexer/lexer.h"
#include
#include "libpspp/cast.h"
#include "gl/minmax.h"
static const struct lex_reader_class lex_gtk_text_buffer_reader_class ;
struct lex_gtk_text_buffer_reader
{
struct lex_reader reader;
/* The GtkTextBuffer from which we are reading. */
GtkTextBuffer *buffer;
GtkTextIter start;
GtkTextIter stop;
/* Text pulled from part of the GtkTextBuffer. */
gchar *part;
gsize part_len; /* Number of bytes in 'part'. */
gsize part_ofs; /* Current offset into 'part'. */
};
static struct lex_gtk_text_buffer_reader *
lex_gtk_text_buffer_reader_cast (struct lex_reader *r)
{
return UP_CAST (r, struct lex_gtk_text_buffer_reader, reader);
}
struct lex_reader *
lex_reader_for_gtk_text_buffer (GtkTextBuffer *buffer,
GtkTextIter start, GtkTextIter stop,
enum segmenter_mode syntax_mode)
{
struct lex_gtk_text_buffer_reader *r = xmalloc (sizeof *r);
lex_reader_init (&r->reader, &lex_gtk_text_buffer_reader_class);
r->reader.syntax = syntax_mode;
r->reader.line_number = gtk_text_iter_get_line (&start) + 1;
r->buffer = buffer;
g_object_ref (buffer);
r->start = start;
r->stop = stop;
r->part = NULL;
r->part_len = 0;
r->part_ofs = 0;
return &r->reader;
}
static size_t
lex_gtk_text_buffer_read (struct lex_reader *r_, char *buf, size_t n,
enum prompt_style prompt_style UNUSED)
{
struct lex_gtk_text_buffer_reader *r = lex_gtk_text_buffer_reader_cast (r_);
gsize chunk;
if (r->part_ofs == r->part_len)
{
/* Read up to N characters into r->part. N characters might be more than
N bytes, but that's OK: we'll just buffer up some of those bytes for
the next read. */
int n_chars = n;
GtkTextIter iter = r->start ;
int offset = gtk_text_iter_get_offset (&iter);
int end_offset = gtk_text_iter_get_offset (&r->stop);
if (end_offset - offset < n) n_chars = end_offset - offset; gtk_text_iter_set_offset (&iter, offset + n_chars); g_free (r->part);
r->part = gtk_text_iter_get_text (&r->start, &iter);
r->part_len = strlen (r->part);
r->part_ofs = 0;
r->start = iter;
}
chunk = MIN (r->part_len - r->part_ofs, n);
memcpy (buf, r->part + r->part_ofs, chunk);
r->part_ofs += chunk;
return chunk;
}
static void
lex_gtk_text_buffer_close (struct lex_reader *r_)
{
struct lex_gtk_text_buffer_reader *r = lex_gtk_text_buffer_reader_cast (r_);
g_object_unref (r->buffer);
g_free (r->part);
g_free (r);
}
static const struct lex_reader_class lex_gtk_text_buffer_reader_class =
{
lex_gtk_text_buffer_read,
lex_gtk_text_buffer_close
};