[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
gEDA-dev: [RFC][PATCH] Making libgeda load from buffers
Hi folks,
In my quest for integrated support of part databases into gschem, I realised
that libgeda has no way to load schematics or symbols from a memory buffer:
all of the object read commands require the presence of a file pointer.
Ideally, I would have liked to implement reading from memory using memory
streams, but then I realised they were a GNU extension to libc.
What I've done in the attached patches is the following: I've added a new text
buffer system (s_textbuffer.c) that basically lets you iterate over the lines
of a string in memory, doing appropriate bounds checking. I've then modified
all of the commands used when parsing schematics/symbols to use this API.
Now, I'm sure there's a **much** more elegant way to do this, and I'd very
much like someone to point it out. The changes are pretty well contained
within the read functions, so as long as I get to keep my o_read_buffer()
function, I don't really mind how it's implemented.
Peter
--
Fisher Society committee http://tinyurl.com/o39w2
CUSBC novices, match and league secretary http://tinyurl.com/mwrc9
CU Spaceflight http://tinyurl.com/ognu2
09f911029d74e35bd84156c5635688c0 peter-b.co.uk
PGP signature
Add managed text buffers to libgeda.
From: Peter TB Brett <peter@peter-b.co.uk>
In order to facilitate loading symbols & schematics from
memory without an extensive rewrite, this patch adds an API
for reading memory arrays a bit like a file.
Using memory streams & fgets would be nicer, but unfortunately
memory streams are a GNU libc extension.
---
libgeda/include/prototype.h | 6 +
libgeda/include/struct.h | 5 +
libgeda/src/Makefile.am | 2
libgeda/src/s_textbuffer.c | 192 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 204 insertions(+), 1 deletions(-)
diff --git a/libgeda/include/prototype.h b/libgeda/include/prototype.h
index 0aacafc..b105588 100644
--- a/libgeda/include/prototype.h
+++ b/libgeda/include/prototype.h
@@ -635,3 +635,9 @@ char *u_basic_breakup_string(char *string, char delimiter, int count);
void u_basic_strip_trailing(char *string, char c);
int u_basic_has_trailing(char *string, char c);
int u_basic_count_char(const char *string, char character);
+
+/* s_textbuffer.c */
+TextBuffer *s_textbuffer_new (gchar *data, const gint size);
+TextBuffer *s_textbuffer_free (TextBuffer *tb);
+void s_textbuffer_seek (TextBuffer *tb, const gint offset);
+const gchar *s_textbuffer_next (TextBuffer *tb, const gsize count);
diff --git a/libgeda/include/struct.h b/libgeda/include/struct.h
index 8b4e9c8..47b9062 100644
--- a/libgeda/include/struct.h
+++ b/libgeda/include/struct.h
@@ -952,4 +952,9 @@ struct st_page_smob {
PAGE *page;
};
+/* Managed text buffers
+ * ==================== */
+
+typedef struct _TextBuffer TextBuffer;
+
#endif
diff --git a/libgeda/src/Makefile.am b/libgeda/src/Makefile.am
index af773ab..ed03681 100644
--- a/libgeda/src/Makefile.am
+++ b/libgeda/src/Makefile.am
@@ -20,7 +20,7 @@ libgeda_la_SOURCES = \
o_pin_basic.c o_image.c o_embed.c \
u_basic.c s_attrib.c s_basic.c \
s_clib.c s_encoding.c s_hierarchy.c s_papersizes.c s_stretch.c \
- s_log.c \
+ s_log.c s_textbuffer.c \
s_page.c s_slib.c s_color.c s_undo.c s_conn.c \
s_cue.c s_tile.c s_menu.c s_toplevel.c g_smob.c libgeda.c \
g_register.c g_rc.c i_vars.c o_picture.c gdk-pixbuf-hacks.c
diff --git a/libgeda/src/s_textbuffer.c b/libgeda/src/s_textbuffer.c
new file mode 100644
index 0000000..2472143
--- /dev/null
+++ b/libgeda/src/s_textbuffer.c
@@ -0,0 +1,192 @@
+/* gEDA - GPL Electronic Design Automation
+ * libgeda - gEDA's library
+ * Copyright (C) 1998-2000 Ales V. Hvezda
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <libguile.h>
+
+#include "defines.h"
+#include "struct.h"
+#include "globals.h"
+#include "o_types.h"
+#include "colors.h"
+#include "i_vars.h"
+#include "prototype.h"
+
+struct _TextBuffer
+{
+ gchar *buffer;
+ gsize size;
+
+ gchar *line;
+ gsize linesize;
+
+ gsize offset;
+};
+
+#define TEXT_BUFFER_LINE_SIZE 1024
+
+/*! \brief Create a new managed text buffer.
+ *
+ * \par Function description
+ * Allocates and initialises a new TextBuffer to manage the given data
+ * buffer.
+ *
+ * If the size argument is negative, assumes that data is
+ * null-terminated.
+ *
+ * \param data The address of the buffer to be managed.
+ * \param size The length of the buffer.
+ * \retval Pointer to a new TextBuffer struct.
+ */
+TextBuffer *s_textbuffer_new (gchar *data, const gint size)
+{
+ TextBuffer *result;
+ gsize realsize;
+
+ g_assert (data != NULL);
+
+ if (size < 0)
+ realsize = strlen(data);
+ else
+ realsize = size;
+
+ result = g_new0(TextBuffer, 1);
+
+ result->buffer = data;
+ result->size = realsize;
+
+ result->linesize = TEXT_BUFFER_LINE_SIZE;
+ result->line = g_malloc(result->linesize);
+
+ return result;
+}
+
+/*! \brief Clean up a managed text buffer
+ *
+ * \par Function description
+ * Cleans up all of the resources associated with a given TextBuffer.
+ *
+ * Should be called thus:
+ *
+ * \code
+ * tb = s_textbuffer_free (tb);
+ * \endcode
+ */
+TextBuffer *s_textbuffer_free (TextBuffer *tb)
+{
+ if (tb == NULL) return NULL;
+
+ g_free (tb->line);
+ tb->line = NULL;
+ g_free (tb);
+ return NULL;
+}
+
+/*! \brief Change the current position within a text buffer
+ *
+ * \par Function description
+ * Changes where the next call to s_textbuffer_next() will start
+ * reading. If offset is negative, it is considered as a distance
+ * from the end of the buffer.
+ *
+ * \param tb A TextBuffer to seek within.
+ * \param offset A new position within the buffer.
+ */
+void s_textbuffer_seek (TextBuffer *tb, const gint offset)
+{
+ gint ofs;
+ gsize realoffset;
+
+ if (tb == NULL) return;
+
+ ofs = offset;
+ if (ofs > tb->size)
+ ofs = tb->size;
+
+ if (ofs < -tb->size)
+ ofs = 0;
+
+ if (ofs < 0)
+ realoffset = tb->size - ofs;
+ else
+ realoffset = ofs;
+
+ tb->offset = realoffset;
+}
+
+/*! \brief Fetch a number of characters from a text buffer
+ *
+ * \par Function description
+ *
+ *
+ * \param
+ */
+const gchar *s_textbuffer_next (TextBuffer *tb, const gsize count)
+{
+ gsize len = count;
+ gsize maxlen = tb->size - tb->offset;
+
+ if (tb == NULL) return NULL;
+
+ if (tb->offset >= tb->size)
+ return NULL;
+
+ if (len > maxlen)
+ len = maxlen;
+
+ if (tb->linesize < len + 1) {
+ tb->line = g_realloc(tb->line, len + 1);
+ tb->linesize = len + 1;
+ }
+
+ strncpy (tb->line, tb->buffer + offset, len);
+ tb->line[len] = 0;
+ tb->offset += len;
+
+ return tb->line;
+}
+
+const gchar *s_textbuffer_next_line (TextBuffer *tb)
+{
+ int len = 0;
+
+ if (tb == NULL) return NULL;
+
+ if (tb->offset >= tb->size)
+ return NULL;
+
+ while ((tb->buffer[tb->offset + len] != '\n')
+ && (len < tb->size - tb->offset)) {
+ len++;
+ }
+
+ return s_textbuffer_next (tb, len);
+}
Make libgeda parse schematics from buffered data.
From: Peter TB Brett <peter@peter-b.co.uk>
In order to support more complex methods of acquiring symbol
data, libgeda needs to be able to load schematics and symbols
directly from a memory buffer as well as from files.
---
libgeda/include/prototype.h | 25 +++++++--
libgeda/src/a_basic.c | 120 +++++++++++++++++++++++++++++--------------
libgeda/src/o_attrib.c | 44 +++++++++-------
libgeda/src/o_picture.c | 36 +++++++------
libgeda/src/o_text_basic.c | 23 +++++---
libgeda/src/s_basic.c | 89 ++++++++++++++++++++++++++++++++
libgeda/src/s_textbuffer.c | 13 +++--
7 files changed, 259 insertions(+), 91 deletions(-)
diff --git a/libgeda/include/prototype.h b/libgeda/include/prototype.h
index b105588..405af9b 100644
--- a/libgeda/include/prototype.h
+++ b/libgeda/include/prototype.h
@@ -2,6 +2,7 @@
void o_save_embedded(TOPLEVEL *w_current, OBJECT *object_list, FILE *fp);
void o_save_write_header(FILE *fp);
int o_save(TOPLEVEL *w_current, const char *filename);
+OBJECT *o_read_buffer(TOPLEVEL *w_current, OBJECT *object_list, char *buffer, const size_t size, const char *name);
OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename);
void o_scale(TOPLEVEL *w_current, OBJECT *list, int x_scale, int y_scale);
@@ -162,7 +163,11 @@ ATTRIB *o_attrib_copy(ATTRIB *list);
void o_attrib_delete(ATTRIB *a_current);
void o_attrib_remove(ATTRIB *list, ATTRIB *remove);
void o_attrib_detach_all(TOPLEVEL *w_current, OBJECT *object_list, OBJECT *main_head);
-OBJECT *o_read_attribs(TOPLEVEL *w_current, FILE *fp, OBJECT *object_to_get_attribs, unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_read_attribs(TOPLEVEL *w_current,
+ OBJECT *object_to_get_attribs,
+ TextBuffer *tb,
+ unsigned int release_ver,
+ unsigned int fileformat_ver);
void o_save_attribs(FILE *fp, ATTRIB *attribs);
int o_attrib_get_name_value(char *string, char **name, char **value);
void o_attrib_free_current(TOPLEVEL *w_current);
@@ -370,8 +375,11 @@ void o_net_consolidate(TOPLEVEL *w_current);
void o_net_modify(TOPLEVEL *w_current, OBJECT *object, int x, int y, int whichone);
/* o_picture.c */
-OBJECT *o_picture_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
- FILE *fp, unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_picture_read(TOPLEVEL *w_current, OBJECT *object_list,
+ const char *first_line,
+ TextBuffer *tb,
+ unsigned int release_ver,
+ unsigned int fileformat_ver);
char *o_picture_save(OBJECT *object);
void o_picture_set_pixbuf(TOPLEVEL *w_current, GdkPixbuf *pixbuf, char *filename);
OBJECT *o_picture_add(TOPLEVEL *w_current, OBJECT *object_list,
@@ -426,7 +434,12 @@ int o_text_width(TOPLEVEL *w_current, char *string, int size);
OBJECT *o_text_create_string(TOPLEVEL *w_current, OBJECT *object_list, char *string, int size, int color, int x, int y, int alignment, int angle);
OBJECT *o_text_add(TOPLEVEL *w_current, OBJECT *object_list, char type, int color, int x, int y, int alignment, int angle, char *string, int size, int visibility, int show_name_value);
void o_text_recalc(TOPLEVEL *w_current, OBJECT *o_current);
-OBJECT *o_text_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[], FILE *fp, unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_text_read(TOPLEVEL *w_current,
+ OBJECT *object_list,
+ const char *first_line,
+ TextBuffer *tb,
+ unsigned int release_ver,
+ unsigned int fileformat_ver);
void o_text_set_info_font(char buf[]);
char *o_text_save(OBJECT *object);
void o_text_recreate(TOPLEVEL *w_current, OBJECT *o_current);
@@ -472,6 +485,7 @@ char *remove_nl(char *string);
char *remove_last_nl(char *string);
char *remove_string(char *string, int start, int end);
char *insert_string(char *string, int start, char *insert_string);
+char *buffer_next_line(const char *buffer, const size_t size, size_t *offset);
char *expand_env_variables(char *string);
/* s_clib.c */
@@ -640,4 +654,5 @@ int u_basic_count_char(const char *string, char character);
TextBuffer *s_textbuffer_new (gchar *data, const gint size);
TextBuffer *s_textbuffer_free (TextBuffer *tb);
void s_textbuffer_seek (TextBuffer *tb, const gint offset);
-const gchar *s_textbuffer_next (TextBuffer *tb, const gsize count);
+gchar *s_textbuffer_next (TextBuffer *tb, const gsize count);
+gchar *s_textbuffer_next_line (TextBuffer *tb);
diff --git a/libgeda/src/a_basic.c b/libgeda/src/a_basic.c
index 1b0e8e5..5e633de 100644
--- a/libgeda/src/a_basic.c
+++ b/libgeda/src/a_basic.c
@@ -288,19 +288,13 @@ int o_save(TOPLEVEL *w_current, const char *filename)
return 1;
}
-/*! \brief Read a file
- * \par Function Description
- * This function reads a file in libgead format.
- *
- * \param [in,out] w_current The current TOPLEVEL structure.
- * \param [in] object_list The object_list to read data to.
- * \param [in] filename The filename to read from.
- * \return object_list if successful read, or NULL on error.
- */
-OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
+OBJECT *o_read_buffer(TOPLEVEL *w_current, OBJECT *object_list,
+ char *buffer, const size_t size,
+ const char *name)
{
- FILE *fp;
- char buf[1024];
+ char *line = NULL;
+ TextBuffer *tb = NULL;
+
char objtype;
OBJECT *object_list_save=NULL;
OBJECT *temp_tail=NULL;
@@ -315,19 +309,24 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
int embedded_level = 0;
+
/* fill version with default file format version (the current one) */
current_fileformat_ver = FILEFORMAT_VERSION;
- fp = fopen(filename, "r");
-
- if (fp == NULL) {
- s_log_message("o_read: Could not open [%s]\n", filename);
+ if (buffer == NULL) {
+ s_log_message("o_read_buffer: Received NULL buffer\n");
return(NULL);
}
- while ( fgets(buf, 1024, fp) != NULL) {
+ tb = s_textbuffer_new (buffer, size);
+ g_assert (tb != NULL);
- sscanf(buf, "%c", &objtype);
+ while (1) {
+
+ line = s_textbuffer_next_line(tb);
+ if (line == NULL) break;
+
+ sscanf(line, "%c", &objtype);
/* Do we need to check the symbol version? Yes, but only if */
/* 1) the last object read was a complex and */
@@ -346,40 +345,42 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
switch (objtype) {
case(OBJ_LINE):
- object_list = (OBJECT *) o_line_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_line_read(w_current, object_list, line,
release_ver, fileformat_ver);
break;
case(OBJ_NET):
- object_list = (OBJECT *) o_net_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_net_read(w_current, object_list, line,
release_ver, fileformat_ver);
break;
case(OBJ_BUS):
- object_list = (OBJECT *) o_bus_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_bus_read(w_current, object_list, line,
release_ver, fileformat_ver);
break;
case(OBJ_BOX):
- object_list = (OBJECT *) o_box_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_box_read(w_current, object_list, line,
release_ver, fileformat_ver);
break;
case(OBJ_PICTURE):
- object_list = (OBJECT *) o_picture_read(w_current, object_list, buf,
- fp,
+ line = g_strdup(line);
+ object_list = (OBJECT *) o_picture_read(w_current, object_list,
+ line, tb,
release_ver, fileformat_ver);
+ g_free (line);
break;
case(OBJ_CIRCLE):
- object_list = (OBJECT *) o_circle_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_circle_read(w_current, object_list, line,
release_ver, fileformat_ver);
break;
case(OBJ_COMPLEX):
case(OBJ_PLACEHOLDER):
- object_list = (OBJECT *) o_complex_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_complex_read(w_current, object_list, line,
release_ver, fileformat_ver);
/* this is necessary because complex may add attributes which float */
@@ -391,20 +392,21 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
break;
case(OBJ_TEXT):
- /* fgets(string, 1024, fp); string lines are now read inside: */
- object_list = (OBJECT *) o_text_read(w_current, object_list, buf,
- fp,
+ line = g_strdup(line);
+ object_list = (OBJECT *) o_text_read(w_current, object_list,
+ line, tb,
release_ver, fileformat_ver);
+ g_free(line);
break;
case(OBJ_PIN):
- object_list = (OBJECT *) o_pin_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_pin_read(w_current, object_list, line,
release_ver, fileformat_ver);
found_pin++;
break;
case(OBJ_ARC):
- object_list = (OBJECT *) o_arc_read(w_current, object_list, buf,
+ object_list = (OBJECT *) o_arc_read(w_current, object_list, line,
release_ver, fileformat_ver);
break;
@@ -412,7 +414,8 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
object_before_attr = object_list;
/* first is the fp */
/* 2nd is the object to get the attributes */
- object_list = (OBJECT *) o_read_attribs(w_current, fp, object_list,
+ object_list = (OBJECT *) o_read_attribs(w_current, object_list,
+ tb,
release_ver, fileformat_ver);
/* by now we have finished reading all the attributes */
@@ -452,7 +455,7 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
} else {
fprintf(stderr, "Read unexpected embedded "
"symbol start marker in [%s] :\n>>\n%s<<\n",
- filename, buf);
+ name, line);
}
break;
@@ -472,7 +475,7 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
} else {
fprintf(stderr, "Read unexpected embedded "
"symbol end marker in [%s] :\n>>\n%s<<\n",
- filename, buf);
+ name, line);
}
break;
@@ -482,7 +485,7 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
break;
case(INFO_FONT):
- o_text_set_info_font(buf);
+ o_text_set_info_font(line);
break;
case(COMMENT):
@@ -490,7 +493,7 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
break;
case(VERSION_CHAR):
- itemsread = sscanf(buf, "v %u %u\n", &release_ver, &fileformat_ver);
+ itemsread = sscanf(line, "v %u %u\n", &release_ver, &fileformat_ver);
/* 20030921 was the last version which did not have a fileformat */
/* version. The below latter test should not happen, but it is here */
@@ -503,18 +506,17 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
if (fileformat_ver < current_fileformat_ver)
{
s_log_message("Read an old format sym/sch file!\n"
- "Please run g[sym|sch]update on:\n[%s]\n", filename);
+ "Please run g[sym|sch]update on:\n[%s]\n", name);
}
break;
default:
fprintf(stderr, "Read garbage in [%s] :\n>>\n%s<<\n",
- filename, buf);
+ name, line);
break;
}
}
- fclose(fp);
/* Was the very last thing we read a complex and has it not been checked */
/* yet? This would happen if the complex is at the very end of the file */
@@ -530,8 +532,48 @@ OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
o_pin_update_whichend(w_current, return_head(object_list), found_pin);
}
}
+
+ tb = s_textbuffer_free(tb);
return(object_list);
+
+}
+
+/*! \brief Read a file
+ * \par Function Description
+ * This function reads a file in libgead format.
+ *
+ * \param [in,out] w_current The current TOPLEVEL structure.
+ * \param [in] object_list The object_list to read data to.
+ * \param [in] filename The filename to read from.
+ * \return object_list if successful read, or NULL on error.
+ */
+OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
+{
+ GError *err = NULL;
+ char *buffer = NULL;
+ size_t size;
+ OBJECT *result = NULL;
+
+ g_file_get_contents(filename, &buffer, &size, &err);
+
+ g_assert ((buffer == NULL && err != NULL)
+ || (buffer != NULL && err == NULL));
+
+ if (err != NULL)
+ {
+ /* Report error to user, and free error */
+ g_assert (buffer == NULL);
+ fprintf (stderr, "o_read: Unable to read file: [%s]\n", err->message);
+ g_error_free (err);
+ return NULL;
+ }
+
+ /* Parse file contents */
+ g_assert (buffer != NULL);
+ result = o_read_buffer (w_current, object_list, buffer, size, filename);
+ g_free (buffer);
+ return result;
}
/*! \brief Scale a set of lines.
diff --git a/libgeda/src/o_attrib.c b/libgeda/src/o_attrib.c
index 49cb79c..0ef513f 100644
--- a/libgeda/src/o_attrib.c
+++ b/libgeda/src/o_attrib.c
@@ -647,37 +647,44 @@ void o_attrib_detach_all(TOPLEVEL *w_current, OBJECT *object_list, OBJECT *main_
#endif
}
-/*! \brief Read attributes from a file.
+/*! \brief Read attributes from a buffer.
* \par Function Description
- * Read attributes from a file.
+ * Read attributes from a buffer.
*
* \param [in] w_current The TOPLEVEL object.
- * \param [in] fp FILE pointer to read from.
* \param [out] object_to_get_attribs Storage for attributes.
+ * \param [in] buffer Data buffer to read from.
+ * \param [in] buffer_size Size of data buffer.
+ * \param [in,out] offset Location of offset of start of attrib block.
* \param [in] release_ver libgeda release version number.
* \param [in] fileformat_ver file format version number.
* \return Pointer to object_to_get_attribs.
*/
-OBJECT *o_read_attribs(TOPLEVEL *w_current, FILE *fp, OBJECT *object_to_get_attribs,
+OBJECT *o_read_attribs(TOPLEVEL *w_current,
+ OBJECT *object_to_get_attribs,
+ TextBuffer *tb,
unsigned int release_ver, unsigned int fileformat_ver)
{
OBJECT *object_list=NULL;
- char buf[1024];
+ char *line = NULL;
char objtype;
int ATTACH=FALSE;
int saved_color = -1;
object_list = object_to_get_attribs;
- while ( fgets(buf, 1024, fp) != NULL) {
+ while (1) {
- sscanf(buf, "%c", &objtype);
+ line = s_textbuffer_next_line (tb);
+ if (line == NULL) break;
+
+ sscanf(line, "%c", &objtype);
switch (objtype) {
case(OBJ_LINE):
object_list = (OBJECT *) o_line_read(w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
break;
@@ -685,21 +692,21 @@ OBJECT *o_read_attribs(TOPLEVEL *w_current, FILE *fp, OBJECT *object_to_get_attr
case(OBJ_NET):
object_list = (OBJECT *) o_net_read(w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
break;
case(OBJ_BUS):
object_list = (OBJECT *) o_bus_read(w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
break;
case(OBJ_BOX):
object_list = (OBJECT *) o_box_read(w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
break;
@@ -707,7 +714,7 @@ OBJECT *o_read_attribs(TOPLEVEL *w_current, FILE *fp, OBJECT *object_to_get_attr
object_list = (OBJECT *) o_circle_read(
w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
break;
@@ -717,7 +724,7 @@ OBJECT *o_read_attribs(TOPLEVEL *w_current, FILE *fp, OBJECT *object_to_get_attr
object_list = (OBJECT *) o_complex_read(
w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
/* this is necessary because complex may add
@@ -730,24 +737,25 @@ OBJECT *o_read_attribs(TOPLEVEL *w_current, FILE *fp, OBJECT *object_to_get_attr
case(OBJ_PIN):
object_list = (OBJECT *) o_pin_read(w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
break;
case(OBJ_ARC):
object_list = (OBJECT *) o_arc_read(w_current,
object_list,
- buf,
+ line,
release_ver, fileformat_ver);
break;
case(OBJ_TEXT):
- /* fgets(string, 1024, fp); text strings are now read inside: */
+ line = g_strdup (line);
object_list = (OBJECT *) o_text_read(w_current,
object_list,
- buf,
- fp,
+ line,
+ tb,
release_ver, fileformat_ver);
+ g_free (line);
saved_color = object_list->color;
ATTACH=TRUE;
diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index e803ef5..aa956d7 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -51,22 +51,26 @@
*
* \param [in] w_current The TOPLEVEL object.
* \param [out] object_list OBJECT list to create picture in.
- * \param [in] buf Character string with picture description.
- * \param [in] fp Picture file to read.
+ * \param [in] first_line Character string with picture description.
+ * \param [in] buffer Buffer containing picture data.
+ * \param [in] buffer_size Length of data buffer.
+ * \param [in,out] offset Location of offset of start of next line.
* \param [in] release_ver libgeda release version number.
* \param [in] fileformat_ver libgeda file format version number.
* \return A pointer to the new picture object.
*/
OBJECT *o_picture_read(TOPLEVEL *w_current, OBJECT *object_list,
- char buf[], FILE *fp,
- unsigned int release_ver,unsigned int fileformat_ver)
+ const char *first_line,
+ TextBuffer *tb,
+ unsigned int release_ver,
+ unsigned int fileformat_ver)
{
int x1, y1;
int width, height, angle;
gchar mirrored, embedded;
int num_conv;
gchar type;
- gchar buffer[MAX_TEXT_LINE_LENGTH];
+ gchar *line = NULL;
gchar *filename;
GdkPixbuf *pixbuf;
static char gdk_initialized=0;
@@ -79,12 +83,12 @@ OBJECT *o_picture_read(TOPLEVEL *w_current, OBJECT *object_list,
gdk_initialized = 1;
}
- num_conv = sscanf(buf, "%c %d %d %d %d %d %c %c\n",
+ num_conv = sscanf(first_line, "%c %d %d %d %d %d %c %c\n",
&type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
if (num_conv != 8) {
- fprintf(stderr, "Error reading picture definition line: %s.\n", buf);
- s_log_message ("Error reading picture definition line: %s.\n", buf);
+ fprintf(stderr, "Error reading picture definition line: %s.\n", first_line);
+ s_log_message ("Error reading picture definition line: %s.\n", first_line);
}
/* Convert from ascii character to number */
@@ -137,11 +141,9 @@ OBJECT *o_picture_read(TOPLEVEL *w_current, OBJECT *object_list,
}
- fgets(buffer, 1024, fp);
-
- filename = g_strdup (buffer);
+ filename = g_strdup(s_textbuffer_next_line(tb));
filename = remove_last_nl(filename);
-
+
pixbuf = NULL;
if (embedded == 0) {
@@ -160,10 +162,12 @@ OBJECT *o_picture_read(TOPLEVEL *w_current, OBJECT *object_list,
/* Read the encoded picture */
do {
- finished = 0;
- fgets(buffer, 1024, fp);
- if (g_strcasecmp(buffer, ".\n") != 0) {
- encoded_picture=g_string_append (encoded_picture, buffer);
+
+ line = s_textbuffer_next_line(tb);
+ if (line == NULL) break;
+
+ if (g_strcasecmp(line, ".\n") != 0) {
+ encoded_picture=g_string_append (encoded_picture, line);
encoded_picture=g_string_append (encoded_picture, "\n");
}
else {
diff --git a/libgeda/src/o_text_basic.c b/libgeda/src/o_text_basic.c
index cd5eff2..85a26d7 100644
--- a/libgeda/src/o_text_basic.c
+++ b/libgeda/src/o_text_basic.c
@@ -1013,7 +1013,9 @@ void o_text_recalc(TOPLEVEL *w_current, OBJECT *o_current)
*
*/
OBJECT *o_text_read(TOPLEVEL *w_current, OBJECT *object_list,
- char buf[], FILE *fp, unsigned int release_ver,
+ const char *first_line,
+ TextBuffer *tb,
+ unsigned int release_ver,
unsigned int fileformat_ver)
{
char type;
@@ -1030,21 +1032,21 @@ OBJECT *o_text_read(TOPLEVEL *w_current, OBJECT *object_list,
GString *textstr;
if (fileformat_ver == 1) {
- sscanf(buf, "%c %d %d %d %d %d %d %d %d %d\n", &type, &x, &y,
+ sscanf(first_line, "%c %d %d %d %d %d %d %d %d %d\n", &type, &x, &y,
&color, &size,
&visibility, &show_name_value,
&angle, &alignment, &num_lines);
} else if (release_ver < VERSION_20000220) {
/* yes, above less than (not less than and equal) is correct. The format */
/* change occurred in 20000220 */
- sscanf(buf, "%c %d %d %d %d %d %d %d\n", &type, &x, &y,
+ sscanf(first_line, "%c %d %d %d %d %d %d %d\n", &type, &x, &y,
&color, &size,
&visibility, &show_name_value,
&angle);
alignment = LOWER_LEFT; /* older versions didn't have this */
num_lines = 1; /* only support a single line */
} else {
- sscanf(buf, "%c %d %d %d %d %d %d %d %d\n", &type, &x, &y,
+ sscanf(first_line, "%c %d %d %d %d %d %d %d %d\n", &type, &x, &y,
&color, &size,
&visibility, &show_name_value,
&angle, &alignment);
@@ -1095,8 +1097,8 @@ OBJECT *o_text_read(TOPLEVEL *w_current, OBJECT *object_list,
}
if (color < 0 || color > MAX_COLORS) {
- fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
- s_log_message("Found an invalid color [ %s ]\n", buf);
+ fprintf(stderr, "Found an invalid color [ %s ]\n", first_line);
+ s_log_message("Found an invalid color [ %s ]\n", first_line);
s_log_message("Setting color to WHITE\n");
color = WHITE;
}
@@ -1105,11 +1107,14 @@ OBJECT *o_text_read(TOPLEVEL *w_current, OBJECT *object_list,
textstr = g_string_new ("");
for (i = 0; i < num_lines; i++) {
- gchar buffer[MAX_TEXT_LINE_LENGTH];
+ gchar *line;
- fgets (buffer, MAX_TEXT_LINE_LENGTH, fp);
+ line = s_textbuffer_next_line (tb);
- textstr = g_string_append (textstr, buffer);
+ if (line != NULL)
+ {
+ textstr = g_string_append (textstr, line);
+ }
}
/* retrieve the character string from the GString */
string = g_string_free (textstr, FALSE);
diff --git a/libgeda/src/s_basic.c b/libgeda/src/s_basic.c
index d60baba..6cef76e 100644
--- a/libgeda/src/s_basic.c
+++ b/libgeda/src/s_basic.c
@@ -845,6 +845,95 @@ char *insert_string(char *string, int start, char *insert_string)
return(new_string);
}
+/*!
+ * \brief Get the next line of a text buffer.
+ *
+ * \par Function Description
+ *
+ * Retrieves the next line of a text data buffer into a
+ * newly-allocated string of the correct size. The size of the
+ * buffer is specified with the size argument, which may be set to
+ * zero or negative if the buffer is null-terminated, in which case
+ * the size argument is ignored. If offset is not NULL, it should be
+ * the location at which buffer_next_line() may store the index of
+ * the character immediately following the last character in the line
+ * (i.e. the line length). If the value of offset is non-zero, it is
+ * taken as the index of the first character of the line.
+ *
+ * If offset is beyond the end of the buffer, or the character at
+ * offset is null, returns a null pointer.
+ *
+ * An example of repeatedly obtaining lines:
+ *
+ * \code
+ * char *buffer, *line;
+ * size_t buffersize
+ * size_t offset = 0;
+ *
+ * // ... initialise buffer ...
+ *
+ * while (line = buffer_next_line (buffer, buffersize, &offset)) {
+ * printf (line);
+ * free (line);
+ * }
+ * \endcode
+ *
+ * \param[in] buffer Buffer to read from
+ * \param[in] size Total size of buffer
+ * \param[in,out] offset Location of offset of beginning of line
+ *
+ * \retval Pointer to newly-allocated string buffer containing line
+ */
+char *buffer_next_line(const char *buffer, const size_t size, size_t *offset)
+{
+ size_t n = 0;
+ size_t ofs = 0;
+ size_t len;
+ char *result;
+
+ g_assert (buffer != NULL);
+
+ /* Use the current value of linelen as the starting offset */
+ if (offset != NULL) ofs = *offset;
+
+ n = ofs;
+
+ if ((size > 0) && (n >= size)) return NULL;
+ if (buffer[n] == 0) return NULL;
+
+ while (1) {
+ /* Check if we've reached the end of the buffer */
+ if ((size > 0) && (n >= size)) {
+ n--;
+ break;
+ }
+ /* Check if we've reached a null */
+ if (buffer[n] == 0) {
+ n--; /* Exclude trailing null */
+ break;
+ }
+ /* Check if we've reached the end of a line */
+ if (buffer[n] == '\n') {
+ break;
+ }
+ n++;
+ }
+
+ /* n now contains the *offset* of the last character we want to
+ * copy, so now we add one and subract the initial offset in order
+ * to find the length to copy. */
+ if (size > 0) g_assert (n < size);
+ len = n + 1 - ofs;
+
+ result = g_strndup (buffer + *offset, len);
+ if (offset != NULL)
+ {
+ *offset += len;/* offset now contains index of first char of next line */
+ }
+ return result;
+}
+
+
/*! \todo Finish function documentation!!!
* \brief
* \par Function Description
diff --git a/libgeda/src/s_textbuffer.c b/libgeda/src/s_textbuffer.c
index 2472143..496b6fb 100644
--- a/libgeda/src/s_textbuffer.c
+++ b/libgeda/src/s_textbuffer.c
@@ -149,13 +149,15 @@ void s_textbuffer_seek (TextBuffer *tb, const gint offset)
*
* \param
*/
-const gchar *s_textbuffer_next (TextBuffer *tb, const gsize count)
+gchar *s_textbuffer_next (TextBuffer *tb, const gsize count)
{
gsize len = count;
gsize maxlen = tb->size - tb->offset;
if (tb == NULL) return NULL;
+ if (count == 0) return NULL;
+
if (tb->offset >= tb->size)
return NULL;
@@ -167,14 +169,15 @@ const gchar *s_textbuffer_next (TextBuffer *tb, const gsize count)
tb->linesize = len + 1;
}
- strncpy (tb->line, tb->buffer + offset, len);
+ strncpy (tb->line, tb->buffer + tb->offset, len);
+
tb->line[len] = 0;
tb->offset += len;
return tb->line;
}
-const gchar *s_textbuffer_next_line (TextBuffer *tb)
+gchar *s_textbuffer_next_line (TextBuffer *tb)
{
int len = 0;
@@ -184,9 +187,11 @@ const gchar *s_textbuffer_next_line (TextBuffer *tb)
return NULL;
while ((tb->buffer[tb->offset + len] != '\n')
- && (len < tb->size - tb->offset)) {
+ && (len < tb->size - tb->offset - 1)) {
len++;
}
+ len++;
+
return s_textbuffer_next (tb, len);
}
_______________________________________________
geda-dev mailing list
geda-dev@moria.seul.org
http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev