b34edf97b7ce430432e0f8af3a6755b6a6dc89c5
[pspp] / src / ui / gui / psppire-lex-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 /* A lex_reader object to read characters directly from a GtkTextBuffer */
18
19 #include <config.h>
20
21 #include "psppire-lex-reader.h"
22 #include "src/language/lexer/lexer.h"
23
24 #include <gtk/gtk.h>
25
26
27 #include "libpspp/cast.h"
28
29 #include "gl/minmax.h"
30
31 static const struct lex_reader_class lex_gtk_text_buffer_reader_class ;
32
33
34 struct lex_gtk_text_buffer_reader
35 {
36   struct lex_reader reader;
37
38   /* The GtkTextBuffer from which we are reading. */
39   GtkTextBuffer *buffer;
40   GtkTextIter start;
41   GtkTextIter stop;
42
43   /* Text pulled from part of the GtkTextBuffer. */
44   gchar *part;
45   gsize part_len;               /* Number of bytes in 'part'. */
46   gsize part_ofs;               /* Current offset into 'part'. */
47 };
48
49 static struct lex_gtk_text_buffer_reader *
50 lex_gtk_text_buffer_reader_cast (struct lex_reader *r)
51 {
52   return UP_CAST (r, struct lex_gtk_text_buffer_reader, reader);
53 }
54
55
56 struct lex_reader *
57 lex_reader_for_gtk_text_buffer (GtkTextBuffer *buffer,
58                                 GtkTextIter start, GtkTextIter stop,
59                                 enum segmenter_mode syntax_mode)
60 {
61   struct lex_gtk_text_buffer_reader *r = xmalloc (sizeof *r);
62
63   lex_reader_init (&r->reader, &lex_gtk_text_buffer_reader_class);
64   r->reader.syntax = syntax_mode;
65   r->reader.line_number = gtk_text_iter_get_line (&start) + 1;
66
67   r->buffer = buffer;
68   g_object_ref (buffer);
69
70   r->start = start;
71   r->stop = stop;
72
73   r->part = NULL;
74   r->part_len = 0;
75   r->part_ofs = 0;
76
77   return &r->reader;
78 }
79
80
81 static size_t
82 lex_gtk_text_buffer_read (struct lex_reader *r_, char *buf, size_t n,
83                  enum prompt_style prompt_style UNUSED)
84 {
85   struct lex_gtk_text_buffer_reader *r = lex_gtk_text_buffer_reader_cast (r_);
86   gsize chunk;
87
88   if (r->part_ofs == r->part_len)
89     {
90       /* Read up to N characters into r->part.  N characters might be more than
91          N bytes, but that's OK: we'll just buffer up some of those bytes for
92          the next read. */
93       int n_chars = n;
94
95       GtkTextIter iter = r->start ;
96
97       int offset = gtk_text_iter_get_offset (&iter);
98       int end_offset = gtk_text_iter_get_offset (&r->stop);
99
100       if (end_offset - offset < n)
101         n_chars = end_offset - offset;
102
103       gtk_text_iter_set_offset (&iter, offset + n_chars);
104
105       g_free (r->part);
106       r->part = gtk_text_iter_get_text (&r->start, &iter);
107       r->part_len = strlen (r->part);
108       r->part_ofs = 0;
109
110       r->start = iter;
111     }
112
113   chunk = MIN (r->part_len - r->part_ofs, n);
114   memcpy (buf, r->part + r->part_ofs, chunk);
115   r->part_ofs += chunk;
116
117   return chunk;
118 }
119
120
121
122 static void
123 lex_gtk_text_buffer_close (struct lex_reader *r_)
124 {
125   struct lex_gtk_text_buffer_reader *r = lex_gtk_text_buffer_reader_cast (r_);
126
127   g_object_unref (r->buffer);
128   g_free (r->part);
129   g_free (r);
130 }
131
132
133 static const struct lex_reader_class lex_gtk_text_buffer_reader_class =
134   {
135     lex_gtk_text_buffer_read,
136     lex_gtk_text_buffer_close
137   };