Bump gEDA version
[geda-gaf.git] / libgeda / src / s_textbuffer.c
blobc78fd38d6bf05bef87d0b3dacd81ad2b161ccdd6
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <config.h>
23 #include <stdio.h>
24 #include <glib.h>
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #endif
30 #include "libgeda_priv.h"
32 struct _TextBuffer
34 const gchar *buffer;
35 gsize size;
37 gchar *line;
38 gsize linesize;
40 gsize offset;
43 #define TEXT_BUFFER_LINE_SIZE 1024
45 /*! \brief Create a new managed text buffer.
47 * \par Function description
48 * Allocates and initialises a new TextBuffer to manage the given data
49 * buffer.
51 * If the size argument is negative, assumes that data is
52 * null-terminated.
54 * \param data The address of the buffer to be managed.
55 * \param size The length of the buffer.
56 * \retval Pointer to a new TextBuffer struct.
58 TextBuffer *s_textbuffer_new (const gchar *data, const gint size)
60 TextBuffer *result;
61 gsize realsize;
63 g_return_val_if_fail ((data != NULL),
64 NULL);
66 if (size < 0)
67 realsize = strlen(data);
68 else
69 realsize = size;
71 result = g_new0(TextBuffer, 1);
73 result->buffer = data;
74 result->size = realsize;
76 result->linesize = TEXT_BUFFER_LINE_SIZE;
77 result->line = g_malloc(result->linesize);
79 return result;
82 /*! \brief Clean up a managed text buffer
84 * \par Function description
85 * Cleans up all of the resources associated with a given TextBuffer.
87 * Should be called thus:
89 * \code
90 * tb = s_textbuffer_free (tb);
91 * \endcode
93 TextBuffer *s_textbuffer_free (TextBuffer *tb)
95 if (tb == NULL) return NULL;
97 g_free (tb->line);
98 tb->line = NULL;
99 g_free (tb);
100 return NULL;
103 /*! \brief Fetch a number of characters from a text buffer
105 * \par Function description
106 * Get some number of characters from a TextBuffer, starting at the
107 * current position. If the end of the buffer has been reached (and
108 * thus no more characters remain) returns null. If \a count is -1,
109 * obtains all characters up to and including the next newline.
111 * A newline is detected as '\\n', or '\\r' together with its
112 * immediately following '\\n', or '\\r', in that order. All newlines
113 * are collapsed into a single '\\n'.
115 * The returned character array should be considered highly volatile,
116 * and is only valid until the next call to s_textbuffer_next() or
117 * s_textbuffer_next_line().
119 * \param tb TextBuffer to read from.
120 * \param count Maximum number of characters to read.
121 * \retval Character array, or NULL if no characters left.
123 const gchar *
124 s_textbuffer_next (TextBuffer *tb, const gssize count)
126 gboolean eol = FALSE;
127 gchar c;
128 gsize len;
130 g_return_val_if_fail (tb != NULL, NULL);
132 if (tb->offset >= tb->size) return NULL;
134 const gchar *src = tb->buffer + tb->offset;
135 gchar *dest = tb->line;
136 const gchar *buf_end = tb->buffer + tb->size;
138 while (1) {
139 if (src >= buf_end) break;
140 if (count >= 0 && dest - tb->line >= count) break;
141 if (count < 0 && eol) break;
143 /* Expand line buffer, if necessary, leaving space for a null */
144 len = dest - tb->line + 2;
145 if (len >= tb->linesize) {
146 tb->linesize += TEXT_BUFFER_LINE_SIZE;
147 tb->line = g_realloc(tb->line, tb->linesize);
150 eol = FALSE;
151 c = *src;
152 if (c == '\n') {
153 *dest = '\n';
154 eol = TRUE;
155 } else if (c == '\r') {
156 *dest = '\n';
157 eol = TRUE;
158 /* Peek ahead to absorb a '\n' */
159 src++;
160 if (src >= buf_end || *src != '\n') src--;
161 } else {
162 *dest = c;
165 src++;
166 dest++;
169 *dest = 0;
170 tb->offset = src - tb->buffer;
172 return tb->line;
174 /*! \brief Fetch the next line from a text buffer
176 * \par Function description
177 * Get the next line of characters from a TextBuffer, starting from
178 * the current position. If the end of the buffer has been reached
179 * (and thus no more characters remain) returns null.
181 * The returned character array should be considered highly volatile,
182 * and is only valid until the next call to s_textbuffer_next() or
183 * s_textbuffer_next_line().
185 * \param tb TextBuffer to read from.
186 * \retval Character array, or NULL if no characters left.
188 const gchar *
189 s_textbuffer_next_line (TextBuffer *tb)
191 return s_textbuffer_next (tb, -1);