[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: gaf.git: branch: master updated (1.7.2-20111231-53-g31440e0)



The branch, master has been updated
       via  31440e054a54001bf462f7da9d31bfc0f0063d3f (commit)
       via  08844256caf27c2ac0be8614388f6e30c034437d (commit)
       via  fbb6ccced155992563052f4c23ac40dec43998f4 (commit)
       via  815eef2cb1f35519633e6fe93332f39e9743ae6c (commit)
       via  f23d270aa84b07f2ce4336acc658eb9d070a8fbc (commit)
       via  8104930a0523c175987c35e80e33cd8dd4a4a97f (commit)
       via  2c5ec1261714ff0a1157582ef0daead543c1da65 (commit)
       via  f0ac4bcbc0fe5ab0c32e45875003f1be35a7bc1c (commit)
       via  312cd9e728c04bf2e593a81a739a71443b420634 (commit)
       via  5480167063451e1c6cf5701f1b198d896c6adf65 (commit)
       via  b8c34b0fda239294f449010c07e2077736b76c97 (commit)
       via  7b64ae90034cf9a1e655259e071cc9e236b00ff2 (commit)
       via  08573f2f4f53afa3735081ea129cd1d86f14a6a2 (commit)
       via  d978cfae017194ffe79a37c69c7fc1befb727199 (commit)
       via  e09936bfe0b2db080cab5376088f24656b0e2ad7 (commit)
       via  206b5f430917287d4d1d46acd5af32ab8ea34877 (commit)
       via  46ffae4667dda3520b31b92370dcafe1e24017a0 (commit)
       via  3ffd19131319cd74689dcb388e53cf12948c26d5 (commit)
       via  7fa7d9ec42e089fcba9f2876c45330c406b19891 (commit)
       via  5d69c79dbc7be5516cd87d47765a63bdb2dcdd33 (commit)
       via  64a7d0283c3c15e1b27077ee5a9c1ec209c0a807 (commit)
       via  2b025def49c1bfeedb0650b4c34d527fa29a5090 (commit)
       via  b0541a1258d82b40b7b604a15d177780fd1b7cf9 (commit)
       via  8c4438ef6071fede03c687c317a1f9d1489dd5f4 (commit)
       via  4cebffe4ffc464cc16ac08191083deb0cbc76bbc (commit)
       via  09bd3be24aff7139ca4c8d3dc99f520c873a8b2d (commit)
       via  d1305adf92982b3a159707c940bafb8c293223fe (commit)
      from  c6db15997c306c23c02dec9cc8f1e9a645f03fcb (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


=========
 Summary
=========

 docs/scheme-api/geda-scheme.texi                   |    4 +-
 gnetlist/src/gnetlist.c                            |    4 +-
 gschem/src/o_complex.c                             |   43 ++++-
 gschem/src/x_clipboard.c                           |   17 ++-
 gschem/src/x_preview.c                             |   21 ++-
 gschem/src/x_window.c                              |   13 +-
 libgeda/include/libgeda/edaerrors.h                |    1 +
 libgeda/include/libgeda/prototype.h                |    2 +-
 libgeda/include/prototype_priv.h                   |   32 ++--
 libgeda/scheme/Makefile.am                         |    5 +-
 .../scheme/unit-tests/t0203-page-string-syntax.scm |    4 +-
 .../unit-tests/t0204-page-parse-ordering.scm       |   31 ++++
 ...0205-page-parse-unterminated-attribute-list.scm |   17 ++
 .../t0206-page-parse-garbage-attribute.scm         |   18 ++
 .../unit-tests/t0207-page-parse-line-endings.scm   |   25 +++
 libgeda/src/a_basic.c                              |  176 +++++++++++---------
 libgeda/src/o_arc_basic.c                          |   24 ++-
 libgeda/src/o_attrib.c                             |   67 +++++----
 libgeda/src/o_box_basic.c                          |   26 ++-
 libgeda/src/o_bus_basic.c                          |   18 ++-
 libgeda/src/o_circle_basic.c                       |   31 ++--
 libgeda/src/o_complex_basic.c                      |  165 +++++++++---------
 libgeda/src/o_line_basic.c                         |   22 ++-
 libgeda/src/o_net_basic.c                          |   11 +-
 libgeda/src/o_path_basic.c                         |   24 ++-
 libgeda/src/o_picture.c                            |   14 +-
 libgeda/src/o_pin_basic.c                          |   18 ++-
 libgeda/src/o_text_basic.c                         |   51 ++++--
 libgeda/src/s_textbuffer.c                         |  143 ++++++----------
 libgeda/src/scheme_page.c                          |   19 ++-
 30 files changed, 627 insertions(+), 419 deletions(-)
 create mode 100644 libgeda/scheme/unit-tests/t0204-page-parse-ordering.scm
 create mode 100644 libgeda/scheme/unit-tests/t0205-page-parse-unterminated-attribute-list.scm
 create mode 100644 libgeda/scheme/unit-tests/t0206-page-parse-garbage-attribute.scm
 create mode 100644 libgeda/scheme/unit-tests/t0207-page-parse-line-endings.scm


=================
 Commit Messages
=================

commit 08844256caf27c2ac0be8614388f6e30c034437d
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Improve clipboard paste error dialog.

:100644 100644 489915d... a9d3f88... M	gschem/src/x_clipboard.c

commit fbb6ccced155992563052f4c23ac40dec43998f4
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Make file load error dialog more useful.

:100644 100644 20c579c... 8eacd3e... M	gschem/src/x_window.c

commit 815eef2cb1f35519633e6fe93332f39e9743ae6c
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gnetlist: Make file load error message clearer.

:100644 100644 d674bfb... bc4c985... M	gnetlist/src/gnetlist.c

commit f23d270aa84b07f2ce4336acc658eb9d070a8fbc
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Messages in GErrors should not be newline-terminated.

:100644 100644 7b335c8... f354f6a... M	libgeda/src/a_basic.c
:100644 100644 6f32ea8... 2461889... M	libgeda/src/o_arc_basic.c
:100644 100644 de98ca5... 5dae202... M	libgeda/src/o_attrib.c
:100644 100644 5f0f279... 6246f66... M	libgeda/src/o_box_basic.c
:100644 100644 27b2e0f... 58d4db6... M	libgeda/src/o_bus_basic.c
:100644 100644 a5d9145... e534bc4... M	libgeda/src/o_circle_basic.c
:100644 100644 91f6a86... 5688d31... M	libgeda/src/o_complex_basic.c
:100644 100644 7963157... e156b7d... M	libgeda/src/o_line_basic.c
:100644 100644 998853d... a09e625... M	libgeda/src/o_net_basic.c
:100644 100644 140deaa... df94ee8... M	libgeda/src/o_path_basic.c
:100644 100644 8c6c5ca... 31e081b... M	libgeda/src/o_picture.c
:100644 100644 35afaf9... a1e1c2c... M	libgeda/src/o_pin_basic.c
:100644 100644 886746c... 70493c5... M	libgeda/src/o_text_basic.c

commit 8104930a0523c175987c35e80e33cd8dd4a4a97f
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: More robust line ending detection when parsing.
    
    Correctly handle '\r', '\n', and '\r\n' line endings.

:100644 100644 4792ec9... f931cbe... M	libgeda/include/prototype_priv.h
:100644 100644 1fbf626... 6d6a37d... M	libgeda/scheme/Makefile.am
:000000 100644 0000000... 23f5e58... A	libgeda/scheme/unit-tests/t0207-page-parse-line-endings.scm
:100644 100644 d8689b1... 5beb526... M	libgeda/src/s_textbuffer.c

commit 2c5ec1261714ff0a1157582ef0daead543c1da65
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Remove s_textbuffer_seek().
    
    It's never been used anyway.

:100644 100644 a66fc34... 4792ec9... M	libgeda/include/prototype_priv.h
:100644 100644 1e5080a... d8689b1... M	libgeda/src/s_textbuffer.c

commit f0ac4bcbc0fe5ab0c32e45875003f1be35a7bc1c
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Return a const string from s_textbuffer_next etc.
    
    Also constify everywhere that string is used.  This helped identify
    several places to avoid unnecessary strdup()/free() pairs.

:100644 100644 26fbd90... a66fc34... M	libgeda/include/prototype_priv.h
:100644 100644 aac0172... 7b335c8... M	libgeda/src/a_basic.c
:100644 100644 c25e2b5... 6f32ea8... M	libgeda/src/o_arc_basic.c
:100644 100644 70778dd... de98ca5... M	libgeda/src/o_attrib.c
:100644 100644 22f21cd... 5f0f279... M	libgeda/src/o_box_basic.c
:100644 100644 0222daf... 27b2e0f... M	libgeda/src/o_bus_basic.c
:100644 100644 98b08a3... a5d9145... M	libgeda/src/o_circle_basic.c
:100644 100644 6a92272... 91f6a86... M	libgeda/src/o_complex_basic.c
:100644 100644 db841cf... 7963157... M	libgeda/src/o_line_basic.c
:100644 100644 5d0d855... 998853d... M	libgeda/src/o_net_basic.c
:100644 100644 4a61177... 140deaa... M	libgeda/src/o_path_basic.c
:100644 100644 ef958ac... 8c6c5ca... M	libgeda/src/o_picture.c
:100644 100644 377bdc1... 35afaf9... M	libgeda/src/o_pin_basic.c
:100644 100644 4f493d0... 886746c... M	libgeda/src/o_text_basic.c
:100644 100644 785921e... 1e5080a... M	libgeda/src/s_textbuffer.c

commit 312cd9e728c04bf2e593a81a739a71443b420634
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Another unit test for load errors.

:100644 100644 a063cee... 1fbf626... M	libgeda/scheme/Makefile.am
:000000 100644 0000000... c563a0b... A	libgeda/scheme/unit-tests/t0206-page-parse-garbage-attribute.scm

commit 5480167063451e1c6cf5701f1b198d896c6adf65
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Report error on loading an unterminated attribute list.

:100644 100644 f106060... a063cee... M	libgeda/scheme/Makefile.am
:000000 100644 0000000... abdf666... A	libgeda/scheme/unit-tests/t0205-page-parse-unterminated-attribute-list.scm
:100644 100644 d645b85... 70778dd... M	libgeda/src/o_attrib.c

commit b8c34b0fda239294f449010c07e2077736b76c97
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Don't repeatedly reverse new attribute list.
    
    Add a unit test to make sure this is done correctly.

:100644 100644 5dddadf... f106060... M	libgeda/scheme/Makefile.am
:000000 100644 0000000... ae2070f... A	libgeda/scheme/unit-tests/t0204-page-parse-ordering.scm
:100644 100644 9d8876e... aac0172... M	libgeda/src/a_basic.c
:100644 100644 5f1a9ee... d645b85... M	libgeda/src/o_attrib.c

commit 7b64ae90034cf9a1e655259e071cc9e236b00ff2
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Correct error code numbering for EDA_ERRORs.

:100644 100644 4fe4e0e... fa9663f... M	libgeda/include/libgeda/edaerrors.h

commit 08573f2f4f53afa3735081ea129cd1d86f14a6a2
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Correctly checked-cast arguments when creating dialog.

:100644 100644 b9fb922... 489915d... M	gschem/src/x_clipboard.c

commit d978cfae017194ffe79a37c69c7fc1befb727199
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Fix attempt to free uninitialised pointer.

:100644 100644 56fd466... 4a61177... M	libgeda/src/o_path_basic.c

commit e09936bfe0b2db080cab5376088f24656b0e2ad7
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Make sure attributes are stored internally in the same order as before, or
    else the gsymcheck tests will fail.

:100644 100644 06c9381... 9d8876e... M	libgeda/src/a_basic.c

commit 206b5f430917287d4d1d46acd5af32ab8ea34877
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Updated error messages in o_picture_read, o_path_read, and o_text_read to
    follow style of other similar error messages.

:100644 100644 0af5814... 56fd466... M	libgeda/src/o_path_basic.c
:100644 100644 bfedfc4... ef958ac... M	libgeda/src/o_picture.c
:100644 100644 0c2b6c0... 4f493d0... M	libgeda/src/o_text_basic.c

commit 46ffae4667dda3520b31b92370dcafe1e24017a0
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Made edascm_string_format_sym local.

:100644 100644 1ef553a... 229119b... M	libgeda/include/libgedaguile_priv.h
:100644 100644 1268ce6... a9da63e... M	libgeda/src/scheme_init.c
:100644 100644 0f63dba... c647653... M	libgeda/src/scheme_page.c

commit 3ffd19131319cd74689dcb388e53cf12948c26d5
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Updated unit tests for scheme api (string->page function).

:100644 100644 eb6c3fd... 5dddadf... M	libgeda/scheme/Makefile.am
:100644 100644 c05432a... 407005b... M	libgeda/scheme/unit-tests/t0203-page-string-syntax.scm

commit 7fa7d9ec42e089fcba9f2876c45330c406b19891
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Use an "Ok" button instead of "Close" button for dialog box if
    parsing data from clipboard fails.

:100644 100644 27e6e70... b9fb922... M	gschem/src/x_clipboard.c

commit 5d69c79dbc7be5516cd87d47765a63bdb2dcdd33
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Renamed exception invalid-string to string-format in documentation.

:100644 100644 4bcba6e... 7917204... M	docs/scheme-api/geda-scheme.texi

commit 64a7d0283c3c15e1b27077ee5a9c1ec209c0a807
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Rebase fixes for o_picture.c.

:100644 100644 1066498... bfedfc4... M	libgeda/src/o_picture.c

commit 2b025def49c1bfeedb0650b4c34d527fa29a5090
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Changed invalid-string -> string-format

:100644 100644 95aa157... 1ef553a... M	libgeda/include/libgedaguile_priv.h
:100644 100644 657d680... c05432a... M	libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
:100644 100644 9fa7d51... 1268ce6... M	libgeda/src/scheme_init.c
:100644 100644 e2f1c2d... 0f63dba... M	libgeda/src/scheme_page.c

commit b0541a1258d82b40b7b604a15d177780fd1b7cf9
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Changed enum EDA_ERROR_READ -> EDA_ERROR_PARSE, and made replaced G_FILE_ERROR_FAILED by
    EDA_ERROR_READ in appropriate places.

:100644 100644 2b50513... 4fe4e0e... M	libgeda/include/libgeda/edaerrors.h
:100644 100644 aedbba9... 06c9381... M	libgeda/src/a_basic.c
:100644 100644 9a20f43... c25e2b5... M	libgeda/src/o_arc_basic.c
:100644 100644 93da42c... 5f1a9ee... M	libgeda/src/o_attrib.c
:100644 100644 66b97fe... 22f21cd... M	libgeda/src/o_box_basic.c
:100644 100644 c87c01c... 0222daf... M	libgeda/src/o_bus_basic.c
:100644 100644 da43b73... 98b08a3... M	libgeda/src/o_circle_basic.c
:100644 100644 88ad6d0... 6a92272... M	libgeda/src/o_complex_basic.c
:100644 100644 19fb3b7... db841cf... M	libgeda/src/o_line_basic.c
:100644 100644 3ae39fa... 5d0d855... M	libgeda/src/o_net_basic.c
:100644 100644 8a7f2d1... 0af5814... M	libgeda/src/o_path_basic.c
:100644 100644 e8e4d01... 1066498... M	libgeda/src/o_picture.c
:100644 100644 8186b08... 377bdc1... M	libgeda/src/o_pin_basic.c
:100644 100644 664c9c2... 0c2b6c0... M	libgeda/src/o_text_basic.c

commit 8c4438ef6071fede03c687c317a1f9d1489dd5f4
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Improved error reporting/behaviour when a symbol cannot be loaded.

:100644 100644 56f9981... 8f4853c... M	gschem/src/o_complex.c
:100644 100644 810366b... 63206a0... M	gschem/src/x_preview.c

commit 4cebffe4ffc464cc16ac08191083deb0cbc76bbc
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Use GtkMeessageDialog instead of the generic dialog.

:100644 100644 48a8c76... 27e6e70... M	gschem/src/x_clipboard.c

commit 09bd3be24aff7139ca4c8d3dc99f520c873a8b2d
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Fixed missing end of function.

:100644 100644 e4a6072... 4bcba6e... M	docs/scheme-api/geda-scheme.texi

commit d1305adf92982b3a159707c940bafb8c293223fe
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Partial fix for bug #700448.
    
    NULL is returned from o_*_read and o_read_buffer functions if parsing of the input buffer fails.
    An error object is returned in these cases, describing in detail what error occured.
    
    gnetlist is updated to exit with status code 2 if the input file can't be read.
    
    gschem is updated to report errors when using o_read_buffer.
    
    TODO:
    * Prone to segfaults on bad input files (separate patch)

:100644 100644 f7b251c... e4a6072... M	docs/scheme-api/geda-scheme.texi
:100644 100644 4d7120c... d674bfb... M	gnetlist/src/gnetlist.c
:100644 100644 6b692fc... 56f9981... M	gschem/src/o_complex.c
:100644 100644 d89018c... 48a8c76... M	gschem/src/x_clipboard.c
:100644 100644 be76d64... 810366b... M	gschem/src/x_preview.c
:100644 100644 ce7f002... 2b50513... M	libgeda/include/libgeda/edaerrors.h
:100644 100644 9e9f0bc... 56a6cdc... M	libgeda/include/libgeda/prototype.h
:100644 100644 229119b... 95aa157... M	libgeda/include/libgedaguile_priv.h
:100644 100644 927f672... 26fbd90... M	libgeda/include/prototype_priv.h
:100644 100644 e608017... 657d680... M	libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
:100644 100644 9be1f1b... aedbba9... M	libgeda/src/a_basic.c
:100644 100644 52dadaf... 9a20f43... M	libgeda/src/o_arc_basic.c
:100644 100644 cd2cb19... 93da42c... M	libgeda/src/o_attrib.c
:100644 100644 144d89c... 66b97fe... M	libgeda/src/o_box_basic.c
:100644 100644 ac1841e... c87c01c... M	libgeda/src/o_bus_basic.c
:100644 100644 92c839a... da43b73... M	libgeda/src/o_circle_basic.c
:100644 100644 6ae71b2... 88ad6d0... M	libgeda/src/o_complex_basic.c
:100644 100644 887c525... 19fb3b7... M	libgeda/src/o_line_basic.c
:100644 100644 3fa642f... 3ae39fa... M	libgeda/src/o_net_basic.c
:100644 100644 b71e30a... 8a7f2d1... M	libgeda/src/o_path_basic.c
:100644 100644 43b1124... e8e4d01... M	libgeda/src/o_picture.c
:100644 100644 ef91efb... 8186b08... M	libgeda/src/o_pin_basic.c
:100644 100644 2b7afe0... 664c9c2... M	libgeda/src/o_text_basic.c
:100644 100644 a9da63e... 9fa7d51... M	libgeda/src/scheme_init.c
:100644 100644 311abb5... e2f1c2d... M	libgeda/src/scheme_page.c

=========
 Changes
=========

commit 08844256caf27c2ac0be8614388f6e30c034437d
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Improve clipboard paste error dialog.

diff --git a/gschem/src/x_clipboard.c b/gschem/src/x_clipboard.c
index 489915d..a9d3f88 100644
--- a/gschem/src/x_clipboard.c
+++ b/gschem/src/x_clipboard.c
@@ -241,12 +241,14 @@ x_clipboard_get (GSCHEM_TOPLEVEL *w_current)
                                (gchar *) buf, -1, "Clipboard", &err);
 
   if (err) {
-    GtkWidget * dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
-                                      GTK_DIALOG_DESTROY_WITH_PARENT,
-                                      GTK_MESSAGE_ERROR,
-                                      GTK_BUTTONS_OK,
-                                      _("Invalid schematic on clipboard: %s"),
-                                      err->message);
+    GtkWidget * dialog = gtk_message_dialog_new_with_markup
+      (GTK_WINDOW (w_current->main_window),
+       GTK_DIALOG_DESTROY_WITH_PARENT,
+       GTK_MESSAGE_ERROR,
+       GTK_BUTTONS_OK,
+       _("<b>Invalid schematic on clipboard.</b>\n\nAn error occurred while inserting clipboard data: %s."),
+       err->message);
+    gtk_window_set_title (GTK_WINDOW (dialog), _("Clipboard insertion failed"));
 
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);

commit fbb6ccced155992563052f4c23ac40dec43998f4
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Make file load error dialog more useful.

diff --git a/gschem/src/x_window.c b/gschem/src/x_window.c
index 20c579c..8eacd3e 100644
--- a/gschem/src/x_window.c
+++ b/gschem/src/x_window.c
@@ -740,12 +740,13 @@ x_window_open_page (GSCHEM_TOPLEVEL *w_current, const gchar *filename)
       GtkWidget *dialog;
 
       g_warning ("%s\n", err->message);
-      dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
-                                       GTK_DIALOG_DESTROY_WITH_PARENT,
-                                       GTK_MESSAGE_ERROR,
-                                       GTK_BUTTONS_CLOSE,
-                                       "%s",
-                                       err->message);
+      dialog = gtk_message_dialog_new_with_markup
+        (GTK_WINDOW (w_current->main_window),
+         GTK_DIALOG_DESTROY_WITH_PARENT,
+         GTK_MESSAGE_ERROR,
+         GTK_BUTTONS_CLOSE,
+         _("<b>An error occurred while loading the requested file.</b>\n\nLoading from '%s' failed: %s. The gschem log may contain more information."),
+         fn, err->message);
       gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to load file"));
       gtk_dialog_run (GTK_DIALOG (dialog));
       gtk_widget_destroy (dialog);

commit 815eef2cb1f35519633e6fe93332f39e9743ae6c
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gnetlist: Make file load error message clearer.

diff --git a/gnetlist/src/gnetlist.c b/gnetlist/src/gnetlist.c
index d674bfb..bc4c985 100644
--- a/gnetlist/src/gnetlist.c
+++ b/gnetlist/src/gnetlist.c
@@ -230,7 +230,8 @@ void main_prog(void *closure, int argc, char *argv[])
 
       if (!f_open (pr_current, pr_current->page_current, filename, &err)) {
         g_warning ("%s\n", err->message);
-        fprintf (stderr, "%s\n", err->message);
+        fprintf (stderr, "ERROR: Failed to load '%s': %s\n",
+                 filename, err->message);
         g_error_free (err);
 	exit(2);
       }

commit f23d270aa84b07f2ce4336acc658eb9d070a8fbc
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Messages in GErrors should not be newline-terminated.

diff --git a/libgeda/src/a_basic.c b/libgeda/src/a_basic.c
index 7b335c8..f354f6a 100644
--- a/libgeda/src/a_basic.c
+++ b/libgeda/src/a_basic.c
@@ -495,7 +495,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
         itemsread = sscanf(line, "v %u %u\n", &release_ver, &fileformat_ver);
 
         if (itemsread == 0) {
-          g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, "Failed to parse version from buffer.\n");
+          g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, "Failed to parse version from buffer.");
           goto error;
         }
 
diff --git a/libgeda/src/o_arc_basic.c b/libgeda/src/o_arc_basic.c
index 6f32ea8..2461889 100644
--- a/libgeda/src/o_arc_basic.c
+++ b/libgeda/src/o_arc_basic.c
@@ -253,7 +253,7 @@ OBJECT *o_arc_read (TOPLEVEL *toplevel, const char buf[],
   if(release_ver <= VERSION_20000704) {
     if (sscanf(buf, "%c %d %d %d %d %d %d", &type,
 	       &x1, &y1, &radius, &start_angle, &end_angle, &color) != 7) {
-      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object"));
       return NULL;
     }
 
@@ -266,7 +266,7 @@ OBJECT *o_arc_read (TOPLEVEL *toplevel, const char buf[],
     if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d", &type,
 	       &x1, &y1, &radius, &start_angle, &end_angle, &color,
 	       &arc_width, &arc_end, &arc_type, &arc_length, &arc_space) != 12) {
-      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_attrib.c b/libgeda/src/o_attrib.c
index de98ca5..5dae202 100644
--- a/libgeda/src/o_attrib.c
+++ b/libgeda/src/o_attrib.c
@@ -326,14 +326,14 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
       o_attrib_attach (toplevel, new_obj, object_to_get_attribs, FALSE);
       ATTACH=FALSE;
     } else {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Tried to attach a non-text item as an attribute\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Tried to attach a non-text item as an attribute"));
       goto error;
     }
   }
 
   /* The attribute list wasn't terminated, so it's a parse error! */
   g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE,
-               _("Unexpected end-of-file in attribute list\n"));
+               _("Unexpected end-of-file in attribute list"));
 
 error:
   s_delete_object_glist(toplevel, object_list);
diff --git a/libgeda/src/o_box_basic.c b/libgeda/src/o_box_basic.c
index 5f0f279..6246f66 100644
--- a/libgeda/src/o_box_basic.c
+++ b/libgeda/src/o_box_basic.c
@@ -284,7 +284,7 @@ OBJECT *o_box_read (TOPLEVEL *toplevel, const char buf[],
 
     if (sscanf (buf, "%c %d %d %d %d %d\n",
 		&type, &x1, &y1, &width, &height, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object"));
       return NULL;
     }
 
@@ -313,7 +313,7 @@ OBJECT *o_box_read (TOPLEVEL *toplevel, const char buf[],
 		&box_width, &box_end, &box_type, &box_length,
 		&box_space, &box_filling,
 		&fill_width, &angle1, &pitch1, &angle2, &pitch2) != 17) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_bus_basic.c b/libgeda/src/o_bus_basic.c
index 27b2e0f..58d4db6 100644
--- a/libgeda/src/o_bus_basic.c
+++ b/libgeda/src/o_bus_basic.c
@@ -157,14 +157,14 @@ OBJECT *o_bus_read (TOPLEVEL *toplevel, const char buf[],
 
   if (release_ver <= VERSION_20020825) {
     if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object"));
       return NULL;
     }
     ripper_dir = 0;
   } else {
     if (sscanf (buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color,
 		&ripper_dir) != 7) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_circle_basic.c b/libgeda/src/o_circle_basic.c
index a5d9145..e534bc4 100644
--- a/libgeda/src/o_circle_basic.c
+++ b/libgeda/src/o_circle_basic.c
@@ -243,7 +243,7 @@ OBJECT *o_circle_read (TOPLEVEL *toplevel, const char buf[],
      * to default.
      */
     if (sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color) != 5) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object"));
       return NULL;
     }
 
@@ -272,7 +272,7 @@ OBJECT *o_circle_read (TOPLEVEL *toplevel, const char buf[],
 	       &circle_width, &circle_end, &circle_type,
 	       &circle_length, &circle_space, &circle_fill,
 	       &fill_width, &angle1, &pitch1, &angle2, &pitch2) != 16) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_complex_basic.c b/libgeda/src/o_complex_basic.c
index 91f6a86..5688d31 100644
--- a/libgeda/src/o_complex_basic.c
+++ b/libgeda/src/o_complex_basic.c
@@ -651,7 +651,7 @@ OBJECT *o_complex_read (TOPLEVEL *toplevel,
 
   if (sscanf(buf, "%c %d %d %d %d %d %s\n",
 	     &type, &x1, &y1, &selectable, &angle, &mirror, basename) != 7) {
-    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse complex object\n"));
+    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse complex object"));
     return NULL;
   }
 
diff --git a/libgeda/src/o_line_basic.c b/libgeda/src/o_line_basic.c
index 7963157..e156b7d 100644
--- a/libgeda/src/o_line_basic.c
+++ b/libgeda/src/o_line_basic.c
@@ -226,7 +226,7 @@ OBJECT *o_line_read (TOPLEVEL *toplevel, const char buf[],
      */
     if (sscanf (buf, "%c %d %d %d %d %d\n", &type,
 		&x1, &y1, &x2, &y2, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse line object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse line object"));
       return NULL;
     }
 
@@ -244,7 +244,7 @@ OBJECT *o_line_read (TOPLEVEL *toplevel, const char buf[],
       if (sscanf (buf, "%c %d %d %d %d %d %d %d %d %d %d\n", &type,
 		  &x1, &y1, &x2, &y2, &color,
 		  &line_width, &line_end, &line_type, &line_length, &line_space) != 11) {
-        g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse line object\n"));
+        g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse line object"));
         return NULL;
       }
   }
diff --git a/libgeda/src/o_net_basic.c b/libgeda/src/o_net_basic.c
index 998853d..a09e625 100644
--- a/libgeda/src/o_net_basic.c
+++ b/libgeda/src/o_net_basic.c
@@ -153,7 +153,7 @@ OBJECT *o_net_read (TOPLEVEL *toplevel, const char buf[],
   int color;
 
   if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
-        g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse net object\n"));
+        g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse net object"));
     return NULL;
   }
 
diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index 140deaa..df94ee8 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -178,7 +178,7 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
 	      &type, &color, &line_width, &line_end, &line_type,
 	      &line_length, &line_space, &fill_type, &fill_width, &angle1,
 	      &pitch1, &angle2, &pitch2, &num_lines) != 14) {
-    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse path object\n"));
+    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse path object"));
     return NULL;
   }
 
@@ -204,7 +204,7 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
     line = s_textbuffer_next_line (tb);
 
     if (line == NULL) {
-      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file when reading path\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file when reading path"));
       return NULL;
     }
 
diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index 8c6c5ca..31e081b 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -69,7 +69,7 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
 	 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
   
   if (num_conv != 8) {
-    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse picture definition\n"));
+    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse picture definition"));
     return NULL;
   }
 
diff --git a/libgeda/src/o_pin_basic.c b/libgeda/src/o_pin_basic.c
index 35afaf9..a1e1c2c 100644
--- a/libgeda/src/o_pin_basic.c
+++ b/libgeda/src/o_pin_basic.c
@@ -157,7 +157,7 @@ OBJECT *o_pin_read (TOPLEVEL *toplevel, const char buf[],
 
   if (release_ver <= VERSION_20020825) {
     if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object"));
       return NULL;
     }
     pin_type = PIN_TYPE_NET;
@@ -165,7 +165,7 @@ OBJECT *o_pin_read (TOPLEVEL *toplevel, const char buf[],
   } else {
     if (sscanf (buf, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2,
 		&color, &pin_type, &whichend) != 8) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_text_basic.c b/libgeda/src/o_text_basic.c
index 886746c..70493c5 100644
--- a/libgeda/src/o_text_basic.c
+++ b/libgeda/src/o_text_basic.c
@@ -353,7 +353,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 	       &color, &size,
 	       &visibility, &show_name_value, 
 	       &angle, &alignment, &num_lines) != 10) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object"));
       return NULL;
     }
   } else if (release_ver < VERSION_20000220) {
@@ -363,7 +363,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 	       &color, &size,
 	       &visibility, &show_name_value, 
 	       &angle) != 8) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object"));
       return NULL;
     }
     alignment = LOWER_LEFT; /* older versions didn't have this */
@@ -373,7 +373,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 	       &color, &size,
 	       &visibility, &show_name_value, 
            &angle, &alignment) != 9) {
-      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object"));
       return NULL;
     }
     num_lines = 1; /* only support a single line */
@@ -437,7 +437,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 
     if (line == NULL) {
       g_string_free (textstr, TRUE);
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file after %d lines\n"), i);
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file after %d lines"), i);
       return NULL;
     }
 

commit 8104930a0523c175987c35e80e33cd8dd4a4a97f
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: More robust line ending detection when parsing.
    
    Correctly handle '\r', '\n', and '\r\n' line endings.

diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index 4792ec9..f931cbe 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -237,7 +237,7 @@ double s_path_shortest_distance (PATH *path, int x, int y, int solid);
 /* s_textbuffer.c */
 TextBuffer *s_textbuffer_new (const gchar *data, const gint size);
 TextBuffer *s_textbuffer_free (TextBuffer *tb);
-const gchar *s_textbuffer_next (TextBuffer *tb, const gsize count);
+const gchar *s_textbuffer_next (TextBuffer *tb, const gssize count);
 const gchar *s_textbuffer_next_line (TextBuffer *tb);
 
 /* s_tile.c */
diff --git a/libgeda/scheme/Makefile.am b/libgeda/scheme/Makefile.am
index 1fbf626..6d6a37d 100644
--- a/libgeda/scheme/Makefile.am
+++ b/libgeda/scheme/Makefile.am
@@ -32,6 +32,7 @@ TESTS = unit-tests/t0001-geda-conf-lib.scm \
 	unit-tests/t0204-page-parse-ordering.scm \
 	unit-tests/t0205-page-parse-unterminated-attribute-list.scm \
 	unit-tests/t0206-page-parse-garbage-attribute.scm \
+	unit-tests/t0207-page-parse-line-endings.scm \
 	unit-tests/t0300-attribute.scm \
 	unit-tests/t0301-promotable-attributes.scm \
 	unit-tests/t0400-os.scm \
diff --git a/libgeda/scheme/unit-tests/t0207-page-parse-line-endings.scm b/libgeda/scheme/unit-tests/t0207-page-parse-line-endings.scm
new file mode 100644
index 0000000..23f5e58
--- /dev/null
+++ b/libgeda/scheme/unit-tests/t0207-page-parse-line-endings.scm
@@ -0,0 +1,25 @@
+;; Test that when we load a schematic file, different line endings are
+;; dealt with properly.
+
+(use-modules (unit-test)
+             (geda page)
+             (geda object)
+             (geda attrib))
+
+(define test-page-unix
+  "v 20111231 2\nL 0 0 1000 0 3 0 0 0 -1 -1\nT 0 1000 5 10 1 0 0 0 1\nattrib2=bar")
+(define test-page-dos
+  "v 20111231 2\r\nL 0 0 1000 0 3 0 0 0 -1 -1\r\nT 0 1000 5 10 1 0 0 0 1\r\nattrib2=bar")
+(define test-page-mac
+  "v 20111231 2\rL 0 0 1000 0 3 0 0 0 -1 -1\rT 0 1000 5 10 1 0 0 0 1\rattrib2=bar")
+
+(define (test-func data)
+  (let* ((A (string->page "test/page/A" data))
+         (lst (page-contents A)))
+    (assert-true (line? (list-ref lst 0)))
+    (assert-true (text? (list-ref lst 1)))
+    (assert-equal "attrib2=bar" (text-string (list-ref lst 1)))))
+
+(begin-test 'parse-unix-line-endings (test-func test-page-unix))
+(begin-test 'parse-dos-line-endings (test-func test-page-dos))
+(begin-test 'parse-mac-line-endings (test-func test-page-mac))
diff --git a/libgeda/src/s_textbuffer.c b/libgeda/src/s_textbuffer.c
index d8689b1..5beb526 100644
--- a/libgeda/src/s_textbuffer.c
+++ b/libgeda/src/s_textbuffer.c
@@ -109,7 +109,12 @@ TextBuffer *s_textbuffer_free (TextBuffer *tb)
  *  \par Function description
  *  Get some number of characters from a TextBuffer, starting at the
  *  current position.  If the end of the buffer has been reached (and
- *  thus no more characters remain) returns null.
+ *  thus no more characters remain) returns null.  If \a count is -1,
+ *  obtains all characters up to and including the next newline.
+ *
+ *  A newline is detected as '\n', or '\r' together with its
+ *  immediately following '\n', or '\r', in that order.  All newlines
+ *  are collapsed into a single '\n'.
  *
  *  The returned character array should be considered highly volatile,
  *  and is only valid until the next call to s_textbuffer_next() or
@@ -120,30 +125,53 @@ TextBuffer *s_textbuffer_free (TextBuffer *tb)
  *  \retval      Character array, or NULL if no characters left.
  */
 const gchar *
-s_textbuffer_next (TextBuffer *tb, const gsize count)
+s_textbuffer_next (TextBuffer *tb, const gssize 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;
-
-  if (len > maxlen) 
-    len = maxlen;
-
-  if (tb->linesize < len + 1) {
-    tb->line = g_realloc(tb->line, len + 1);
-    tb->linesize = len + 1;
+  gboolean eol = FALSE;
+  gchar c;
+  gsize len;
+
+  g_return_val_if_fail (tb != NULL, NULL);
+
+  if (tb->offset >= tb->size) return NULL;
+
+  const gchar *src = tb->buffer + tb->offset;
+  gchar *dest = tb->line;
+  const gchar *buf_end = tb->buffer + tb->size;
+
+  while (1) {
+    if (src >= buf_end) break;
+    if (count >= 0 && dest - tb->line >= count) break;
+    if (count < 0 && eol) break;
+
+    /* Expand line buffer, if necessary, leaving space for a null */
+    len = dest - tb->line + 2;
+    if (len >= tb->linesize) {
+      tb->linesize += TEXT_BUFFER_LINE_SIZE;
+      tb->line = g_realloc(tb->line, tb->linesize);
+    }
+
+    eol = FALSE;
+    c = *src;
+    if (c == '\n') {
+      *dest = '\n';
+      eol = TRUE;
+    } else if (c == '\r') {
+      *dest = '\n';
+      eol = TRUE;
+      /* Peek ahead to absorb a '\n' */
+      src++;
+      if (src >= buf_end || *src != '\n') src--;
+    } else {
+      *dest = c;
+    }
+
+    src++;
+    dest++;
   }
 
-  strncpy (tb->line, tb->buffer + tb->offset, len);
-
-  tb->line[len] = 0;
-  tb->offset += len;
+  *dest = 0;
+  tb->offset = src - tb->buffer;
 
   return tb->line;
 }
@@ -164,34 +192,5 @@ s_textbuffer_next (TextBuffer *tb, const gsize count)
 const gchar *
 s_textbuffer_next_line (TextBuffer *tb)
 {
-  int len = 0;
-  gchar *line;
-
-  if (tb == NULL) return NULL;
-
-  if (tb->offset >= tb->size) 
-    return NULL;
-
-  /* skip leading CR characters */
-  while (tb->buffer[tb->offset] == '\r'
-	 && tb->offset < tb->size - 1) {
-    tb->offset += 1;
-  }
-
-  while ((tb->buffer[tb->offset + len] != '\n')
-	 && (len < tb->size - tb->offset - 1)) {
-    len++;
-  }
-
-  len++;
-
-  line = (gchar *) s_textbuffer_next (tb, len);
-
-  /* wipe out all trailing CR characters */
-  while (len > 1 && line[len-2] == '\r') {
-    line[len-1] = 0;
-    len--;
-  }
-
-  return line;
+  return s_textbuffer_next (tb, -1);
 }

commit 2c5ec1261714ff0a1157582ef0daead543c1da65
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Remove s_textbuffer_seek().
    
    It's never been used anyway.

diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index a66fc34..4792ec9 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -237,7 +237,6 @@ double s_path_shortest_distance (PATH *path, int x, int y, int solid);
 /* s_textbuffer.c */
 TextBuffer *s_textbuffer_new (const 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);
 const gchar *s_textbuffer_next_line (TextBuffer *tb);
 
diff --git a/libgeda/src/s_textbuffer.c b/libgeda/src/s_textbuffer.c
index 1e5080a..d8689b1 100644
--- a/libgeda/src/s_textbuffer.c
+++ b/libgeda/src/s_textbuffer.c
@@ -104,38 +104,6 @@ TextBuffer *s_textbuffer_free (TextBuffer *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

commit f0ac4bcbc0fe5ab0c32e45875003f1be35a7bc1c
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Return a const string from s_textbuffer_next etc.
    
    Also constify everywhere that string is used.  This helped identify
    several places to avoid unnecessary strdup()/free() pairs.

diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index 26fbd90..a66fc34 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -70,7 +70,7 @@ void m_transform_scale(TRANSFORM *transform, gdouble factor);
 void m_transform_translate(TRANSFORM *transform, gdouble dx, gdouble dy);
 
 /* o_arc_basic.c */
-OBJECT *o_arc_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_arc_read(TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_arc_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_arc_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_arc_print_solid(TOPLEVEL *toplevel, FILE *fp, int x, int y, int radius, int angle1, int angle2, int color, int arc_width, int length, int space, int origin_x, int origin_y);
@@ -100,7 +100,7 @@ void o_emit_pre_change_notify(TOPLEVEL *toplevel, OBJECT *object);
 void o_emit_change_notify(TOPLEVEL *toplevel, OBJECT *object);
 
 /* o_box_basic.c */
-OBJECT *o_box_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_box_read(TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_box_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_box_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_box_print_solid(TOPLEVEL *toplevel, FILE *fp, int x, int y, int width, int height, int color, int line_width, int length, int space, int origin_x, int origin_y);
@@ -117,7 +117,7 @@ gboolean o_box_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object
 void o_box_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_bus_basic.c */
-OBJECT *o_bus_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_bus_read(TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_bus_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_bus_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void world_get_bus_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top, int *right, int *bottom);
@@ -125,7 +125,7 @@ gboolean o_bus_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object
 void o_bus_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_circle_basic.c */
-OBJECT *o_circle_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_circle_read(TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_circle_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_circle_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_circle_print_solid(TOPLEVEL *toplevel, FILE *fp, int x, int y, int radius, int color, int circle_width, int length, int space, int origin_x, int origin_y);
@@ -142,7 +142,7 @@ gboolean o_circle_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *obj
 void o_circle_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_complex_basic.c */
-OBJECT *o_complex_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_complex_read(TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_complex_save(TOPLEVEL *toplevel, OBJECT *object);
 double o_complex_shortest_distance(OBJECT *object, int x, int y, int force_soild);
 void world_get_complex_bounds(TOPLEVEL *toplevel, OBJECT *complex, int *left, int *top, int *right, int *bottom);
@@ -151,7 +151,7 @@ void o_complex_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 GList *o_complex_get_promotable (TOPLEVEL *toplevel, OBJECT *object, int detach);
 
 /* o_line_basic.c */
-OBJECT *o_line_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_line_read(TOPLEVEL *toplevel, const const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_line_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_line_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_line_print_solid(TOPLEVEL *toplevel, FILE *fp, int x1, int y1, int x2, int y2, int color, int line_width, int length, int space, int origin_x, int origin_y);
@@ -165,7 +165,7 @@ gboolean o_line_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *objec
 void o_line_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_net_basic.c */
-OBJECT *o_net_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_net_read(TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_net_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_net_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void world_get_net_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top, int *right, int *bottom);
@@ -195,7 +195,7 @@ void o_picture_embed(TOPLEVEL *toplevel, OBJECT *object);
 void o_picture_unembed(TOPLEVEL *toplevel, OBJECT *object);
 
 /* o_pin_basic.c */
-OBJECT *o_pin_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
+OBJECT *o_pin_read(TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_pin_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_pin_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void world_get_pin_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top, int *right, int *bottom);
@@ -235,11 +235,11 @@ int s_path_to_polygon(PATH *path, GArray *points);
 double s_path_shortest_distance (PATH *path, int x, int y, int solid);
 
 /* s_textbuffer.c */
-TextBuffer *s_textbuffer_new (gchar *data, const gint size);
+TextBuffer *s_textbuffer_new (const gchar *data, const gint size);
 TextBuffer *s_textbuffer_free (TextBuffer *tb);
 void s_textbuffer_seek (TextBuffer *tb, const gint offset);
-gchar *s_textbuffer_next (TextBuffer *tb, const gsize count);
-gchar *s_textbuffer_next_line (TextBuffer *tb);
+const gchar *s_textbuffer_next (TextBuffer *tb, const gsize count);
+const gchar *s_textbuffer_next_line (TextBuffer *tb);
 
 /* s_tile.c */
 void s_tile_init(TOPLEVEL *toplevel, PAGE *p_current);
diff --git a/libgeda/src/a_basic.c b/libgeda/src/a_basic.c
index aac0172..7b335c8 100644
--- a/libgeda/src/a_basic.c
+++ b/libgeda/src/a_basic.c
@@ -270,7 +270,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
                       char *buffer, const int size,
                       const char *name, GError **err)
 {
-  char *line = NULL;
+  const char *line = NULL;
   TextBuffer *tb = NULL;
 
   char objtype;
@@ -345,9 +345,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
         break;
 
       case(OBJ_PICTURE):
-        line = g_strdup (line);
         new_obj = o_picture_read (toplevel, line, tb, release_ver, fileformat_ver, err);
-        g_free (line);
         if (new_obj == NULL)
           goto error;
         new_object_list = g_list_prepend (new_object_list, new_obj);
@@ -370,18 +368,14 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
         break;
 
       case(OBJ_TEXT):
-        line = g_strdup (line);
         new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err);
-        g_free (line);
         if (new_obj == NULL)
           goto error;
         new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_PATH):
-        line = g_strdup(line);
         new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err);
-        g_free (line);
         if (new_obj == NULL)
           goto error;
         new_object_list = g_list_prepend (new_object_list, new_obj);
diff --git a/libgeda/src/o_arc_basic.c b/libgeda/src/o_arc_basic.c
index c25e2b5..6f32ea8 100644
--- a/libgeda/src/o_arc_basic.c
+++ b/libgeda/src/o_arc_basic.c
@@ -232,7 +232,7 @@ void o_arc_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in] fileformat_ver
  *  \return The ARC OBJECT that was created, or NULL on error.
  */
-OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[],
+OBJECT *o_arc_read (TOPLEVEL *toplevel, const char buf[],
            unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_attrib.c b/libgeda/src/o_attrib.c
index 70778dd..de98ca5 100644
--- a/libgeda/src/o_attrib.c
+++ b/libgeda/src/o_attrib.c
@@ -239,7 +239,7 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
 {
   GList *object_list = NULL;
   OBJECT *new_obj;
-  char *line = NULL;
+  const char *line = NULL;
   char objtype;
   int ATTACH=FALSE;
 
@@ -290,9 +290,7 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
         break;
 
       case(OBJ_PATH):
-        line = g_strdup (line);
         new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err);
-        g_free (line);
         if (new_obj == NULL)
           goto error;
         object_list = g_list_prepend (object_list, new_obj);
@@ -311,9 +309,7 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
         break;
 
       case(OBJ_TEXT):
-        line = g_strdup (line);
         new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err);
-        g_free (line);
         if (new_obj == NULL)
           goto error;
         object_list = g_list_prepend (object_list, new_obj);
diff --git a/libgeda/src/o_box_basic.c b/libgeda/src/o_box_basic.c
index 22f21cd..5f0f279 100644
--- a/libgeda/src/o_box_basic.c
+++ b/libgeda/src/o_box_basic.c
@@ -258,7 +258,7 @@ void o_box_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in]     fileformat_ver  libgeda file format version number.
  *  \return The BOX OBJECT that was created, or NULL on error.
  */
-OBJECT *o_box_read (TOPLEVEL *toplevel, char buf[],
+OBJECT *o_box_read (TOPLEVEL *toplevel, const char buf[],
                     unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_bus_basic.c b/libgeda/src/o_bus_basic.c
index 0222daf..27b2e0f 100644
--- a/libgeda/src/o_bus_basic.c
+++ b/libgeda/src/o_bus_basic.c
@@ -145,7 +145,7 @@ void o_bus_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in] fileformat_ver a integer value of the file format
  *  \return The object list, or NULL on error.
  */
-OBJECT *o_bus_read (TOPLEVEL *toplevel, char buf[],
+OBJECT *o_bus_read (TOPLEVEL *toplevel, const char buf[],
                     unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_circle_basic.c b/libgeda/src/o_circle_basic.c
index 98b08a3..a5d9145 100644
--- a/libgeda/src/o_circle_basic.c
+++ b/libgeda/src/o_circle_basic.c
@@ -222,7 +222,7 @@ void o_circle_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in]  fileformat_ver  libgeda file format version number.
  *  \return A pointer to the new circle object, or NULL on error.
  */
-OBJECT *o_circle_read (TOPLEVEL *toplevel, char buf[],
+OBJECT *o_circle_read (TOPLEVEL *toplevel, const char buf[],
               unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_complex_basic.c b/libgeda/src/o_complex_basic.c
index 6a92272..91f6a86 100644
--- a/libgeda/src/o_complex_basic.c
+++ b/libgeda/src/o_complex_basic.c
@@ -636,7 +636,7 @@ void o_complex_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \return The object list, or NULL on error.
  */
 OBJECT *o_complex_read (TOPLEVEL *toplevel,
-                        char buf[], unsigned int release_ver,
+                        const char buf[], unsigned int release_ver,
                         unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_line_basic.c b/libgeda/src/o_line_basic.c
index db841cf..7963157 100644
--- a/libgeda/src/o_line_basic.c
+++ b/libgeda/src/o_line_basic.c
@@ -206,7 +206,7 @@ void o_line_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in]  fileformat_ver  libgeda file format version number.
  *  \return A pointer to the new line object, or NULL on error.
  */
-OBJECT *o_line_read (TOPLEVEL *toplevel, char buf[],
+OBJECT *o_line_read (TOPLEVEL *toplevel, const char buf[],
                      unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_net_basic.c b/libgeda/src/o_net_basic.c
index 5d0d855..998853d 100644
--- a/libgeda/src/o_net_basic.c
+++ b/libgeda/src/o_net_basic.c
@@ -143,7 +143,7 @@ void o_net_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \return The object list, or NULL on error.
  *
  */
-OBJECT *o_net_read (TOPLEVEL *toplevel, char buf[],
+OBJECT *o_net_read (TOPLEVEL *toplevel, const char buf[],
                     unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index 4a61177..140deaa 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -199,7 +199,7 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
 
   pathstr = g_string_new ("");
   for (i = 0; i < num_lines; i++) {
-    gchar *line;
+    const gchar *line;
 
     line = s_textbuffer_next_line (tb);
 
diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index ef958ac..8c6c5ca 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -60,7 +60,7 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
   int mirrored, embedded;
   int num_conv;
   gchar type;
-  gchar *line = NULL;
+  const gchar *line = NULL;
   gchar *filename;
   gchar *file_content = NULL;
   guint file_length = 0;
diff --git a/libgeda/src/o_pin_basic.c b/libgeda/src/o_pin_basic.c
index 377bdc1..35afaf9 100644
--- a/libgeda/src/o_pin_basic.c
+++ b/libgeda/src/o_pin_basic.c
@@ -144,7 +144,7 @@ void o_pin_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in] fileformat_ver a integer value of the file format
  *  \return The object list, or NULL on error.
  */
-OBJECT *o_pin_read (TOPLEVEL *toplevel, char buf[],
+OBJECT *o_pin_read (TOPLEVEL *toplevel, const char buf[],
                     unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
diff --git a/libgeda/src/o_text_basic.c b/libgeda/src/o_text_basic.c
index 4f493d0..886746c 100644
--- a/libgeda/src/o_text_basic.c
+++ b/libgeda/src/o_text_basic.c
@@ -431,7 +431,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 
   textstr = g_string_new ("");
   for (i = 0; i < num_lines; i++) {
-    gchar *line;
+    const gchar *line;
     
     line = s_textbuffer_next_line (tb);
 
diff --git a/libgeda/src/s_textbuffer.c b/libgeda/src/s_textbuffer.c
index 785921e..1e5080a 100644
--- a/libgeda/src/s_textbuffer.c
+++ b/libgeda/src/s_textbuffer.c
@@ -35,7 +35,7 @@
 
 struct _TextBuffer
 {
-  gchar *buffer;
+  const gchar *buffer;
   gsize size;
 
   gchar *line;
@@ -59,7 +59,7 @@ struct _TextBuffer
  *  \param size The length of the buffer.
  *  \retval Pointer to a new TextBuffer struct.
  */
-TextBuffer *s_textbuffer_new (gchar *data, const gint size)
+TextBuffer *s_textbuffer_new (const gchar *data, const gint size)
 {
   TextBuffer *result;
   gsize realsize;
@@ -151,7 +151,8 @@ void s_textbuffer_seek (TextBuffer *tb, const gint offset)
  *  \param count Maximum number of characters to read.
  *  \retval      Character array, or NULL if no characters left.
  */
-gchar *s_textbuffer_next (TextBuffer *tb, const gsize count)
+const gchar *
+s_textbuffer_next (TextBuffer *tb, const gsize count)
 {
   gsize len = count;
   gsize maxlen = tb->size - tb->offset;
@@ -192,7 +193,8 @@ gchar *s_textbuffer_next (TextBuffer *tb, const gsize count)
  *  \param tb    TextBuffer to read from.
  *  \retval      Character array, or NULL if no characters left.
  */
-gchar *s_textbuffer_next_line (TextBuffer *tb)
+const gchar *
+s_textbuffer_next_line (TextBuffer *tb)
 {
   int len = 0;
   gchar *line;
@@ -215,7 +217,7 @@ gchar *s_textbuffer_next_line (TextBuffer *tb)
 
   len++;
 
-  line = s_textbuffer_next (tb, len);
+  line = (gchar *) s_textbuffer_next (tb, len);
 
   /* wipe out all trailing CR characters */
   while (len > 1 && line[len-2] == '\r') {

commit 312cd9e728c04bf2e593a81a739a71443b420634
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Another unit test for load errors.

diff --git a/libgeda/scheme/Makefile.am b/libgeda/scheme/Makefile.am
index a063cee..1fbf626 100644
--- a/libgeda/scheme/Makefile.am
+++ b/libgeda/scheme/Makefile.am
@@ -31,6 +31,7 @@ TESTS = unit-tests/t0001-geda-conf-lib.scm \
 	unit-tests/t0203-page-string-syntax.scm \
 	unit-tests/t0204-page-parse-ordering.scm \
 	unit-tests/t0205-page-parse-unterminated-attribute-list.scm \
+	unit-tests/t0206-page-parse-garbage-attribute.scm \
 	unit-tests/t0300-attribute.scm \
 	unit-tests/t0301-promotable-attributes.scm \
 	unit-tests/t0400-os.scm \
diff --git a/libgeda/scheme/unit-tests/t0206-page-parse-garbage-attribute.scm b/libgeda/scheme/unit-tests/t0206-page-parse-garbage-attribute.scm
new file mode 100644
index 0000000..c563a0b
--- /dev/null
+++ b/libgeda/scheme/unit-tests/t0206-page-parse-garbage-attribute.scm
@@ -0,0 +1,18 @@
+;; Test that garbage in attribute lists causes a parse error.
+
+(use-modules (unit-test)
+             (geda page)
+             (geda object)
+             (geda attrib))
+
+(define test-page
+"v 20111231 2
+N 0 500 1000 500 4
+{
+T 0 700 5 10 1 0 0 0 1
+attrib1=foo
+__GARBAGE__
+")
+
+(begin-test 'parse-garbage-attribute
+  (assert-thrown 'string-format (string->page "/test/page/A" test-page)))

commit 5480167063451e1c6cf5701f1b198d896c6adf65
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Report error on loading an unterminated attribute list.

diff --git a/libgeda/scheme/Makefile.am b/libgeda/scheme/Makefile.am
index f106060..a063cee 100644
--- a/libgeda/scheme/Makefile.am
+++ b/libgeda/scheme/Makefile.am
@@ -30,6 +30,7 @@ TESTS = unit-tests/t0001-geda-conf-lib.scm \
 	unit-tests/t0202-page-string.scm \
 	unit-tests/t0203-page-string-syntax.scm \
 	unit-tests/t0204-page-parse-ordering.scm \
+	unit-tests/t0205-page-parse-unterminated-attribute-list.scm \
 	unit-tests/t0300-attribute.scm \
 	unit-tests/t0301-promotable-attributes.scm \
 	unit-tests/t0400-os.scm \
diff --git a/libgeda/scheme/unit-tests/t0205-page-parse-unterminated-attribute-list.scm b/libgeda/scheme/unit-tests/t0205-page-parse-unterminated-attribute-list.scm
new file mode 100644
index 0000000..abdf666
--- /dev/null
+++ b/libgeda/scheme/unit-tests/t0205-page-parse-unterminated-attribute-list.scm
@@ -0,0 +1,17 @@
+;; Test that unterminated attribute lists cause a parse error.
+
+(use-modules (unit-test)
+             (geda page)
+             (geda object)
+             (geda attrib))
+
+(define test-page
+"v 20111231 2
+N 0 500 1000 500 4
+{
+T 0 700 5 10 1 0 0 0 1
+attrib1=foo
+")
+
+(begin-test 'parse-unterminated-attribute-list
+  (assert-thrown 'string-format (string->page "/test/page/A" test-page)))
diff --git a/libgeda/src/o_attrib.c b/libgeda/src/o_attrib.c
index d645b85..70778dd 100644
--- a/libgeda/src/o_attrib.c
+++ b/libgeda/src/o_attrib.c
@@ -324,7 +324,6 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
       case(ENDATTACH_ATTR):
         return object_list;
         break;
-
     }
 
     if (ATTACH) {
@@ -336,7 +335,9 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
     }
   }
 
-  return(object_list);
+  /* The attribute list wasn't terminated, so it's a parse error! */
+  g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE,
+               _("Unexpected end-of-file in attribute list\n"));
 
 error:
   s_delete_object_glist(toplevel, object_list);

commit b8c34b0fda239294f449010c07e2077736b76c97
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Don't repeatedly reverse new attribute list.
    
    Add a unit test to make sure this is done correctly.

diff --git a/libgeda/scheme/Makefile.am b/libgeda/scheme/Makefile.am
index 5dddadf..f106060 100644
--- a/libgeda/scheme/Makefile.am
+++ b/libgeda/scheme/Makefile.am
@@ -29,6 +29,7 @@ TESTS = unit-tests/t0001-geda-conf-lib.scm \
 	unit-tests/t0201-page-dirty.scm \
 	unit-tests/t0202-page-string.scm \
 	unit-tests/t0203-page-string-syntax.scm \
+	unit-tests/t0204-page-parse-ordering.scm \
 	unit-tests/t0300-attribute.scm \
 	unit-tests/t0301-promotable-attributes.scm \
 	unit-tests/t0400-os.scm \
diff --git a/libgeda/scheme/unit-tests/t0204-page-parse-ordering.scm b/libgeda/scheme/unit-tests/t0204-page-parse-ordering.scm
new file mode 100644
index 0000000..ae2070f
--- /dev/null
+++ b/libgeda/scheme/unit-tests/t0204-page-parse-ordering.scm
@@ -0,0 +1,31 @@
+;; Test that when we load a schematic file, everything gets connected
+;; in the correct order.
+
+(use-modules (unit-test)
+             (geda page)
+             (geda object)
+             (geda attrib))
+
+(define test-page
+"v 20111231 2
+L 0 0 1000 0 3 0 0 0 -1 -1
+N 0 500 1000 500 4
+{
+T 0 700 5 10 1 0 0 0 1
+attrib1=foo
+T 0 1000 5 10 1 0 0 0 1
+attrib2=bar
+}")
+
+(begin-test 'parse-ordering-objects
+  (let* ((A (string->page "test/page/A" test-page))
+         (lst (page-contents A)))
+    (assert-true (line? (list-ref lst 0)))
+    (assert-true (net? (list-ref lst 1)))
+    (assert-true (text? (list-ref lst 2)))
+    (assert-true (text? (list-ref lst 3)))
+
+    (assert-equal "attrib1=foo" (text-string (list-ref lst 2)))
+    (assert-equal "attrib2=bar" (text-string (list-ref lst 3)))
+
+    (assert-equal (list-tail lst 2) (object-attribs (list-ref lst 1)))))
diff --git a/libgeda/src/a_basic.c b/libgeda/src/a_basic.c
index 9d8876e..aac0172 100644
--- a/libgeda/src/a_basic.c
+++ b/libgeda/src/a_basic.c
@@ -407,8 +407,6 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
           new_attrs_list = o_read_attribs (toplevel, new_obj, tb, release_ver, fileformat_ver, err);
           if (new_attrs_list == NULL)
             goto error;
-
-	  new_attrs_list = g_list_reverse(new_attrs_list);
           new_object_list = g_list_concat (new_attrs_list, new_object_list);
 
           /* by now we have finished reading all the attributes */
diff --git a/libgeda/src/o_attrib.c b/libgeda/src/o_attrib.c
index 5f1a9ee..d645b85 100644
--- a/libgeda/src/o_attrib.c
+++ b/libgeda/src/o_attrib.c
@@ -322,7 +322,6 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
         break;
 
       case(ENDATTACH_ATTR):
-        object_list = g_list_reverse (object_list);
         return object_list;
         break;
 
@@ -336,7 +335,6 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
       goto error;
     }
   }
-  object_list = g_list_reverse (object_list);
 
   return(object_list);
 

commit 7b64ae90034cf9a1e655259e071cc9e236b00ff2
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Correct error code numbering for EDA_ERRORs.

diff --git a/libgeda/include/libgeda/edaerrors.h b/libgeda/include/libgeda/edaerrors.h
index 4fe4e0e..fa9663f 100644
--- a/libgeda/include/libgeda/edaerrors.h
+++ b/libgeda/include/libgeda/edaerrors.h
@@ -26,8 +26,8 @@ G_BEGIN_DECLS
 typedef enum {
   EDA_ERROR_SCHEME,   /* A Scheme error occurred */
   EDA_ERROR_RC_TWICE, /* Attempted to read a configuration file twice */
+  EDA_ERROR_PARSE,    /* A schematic file could not be parsed. */
   EDA_ERROR_NUM_ERRORS,
-  EDA_ERROR_PARSE,
 } EdaError;
 
 GQuark eda_error_quark (void);

commit 08573f2f4f53afa3735081ea129cd1d86f14a6a2
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Correctly checked-cast arguments when creating dialog.

diff --git a/gschem/src/x_clipboard.c b/gschem/src/x_clipboard.c
index b9fb922..489915d 100644
--- a/gschem/src/x_clipboard.c
+++ b/gschem/src/x_clipboard.c
@@ -241,7 +241,7 @@ x_clipboard_get (GSCHEM_TOPLEVEL *w_current)
                                (gchar *) buf, -1, "Clipboard", &err);
 
   if (err) {
-     GtkWidget * dialog = gtk_message_dialog_new (w_current->main_window,
+    GtkWidget * dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
                                       GTK_DIALOG_DESTROY_WITH_PARENT,
                                       GTK_MESSAGE_ERROR,
                                       GTK_BUTTONS_OK,

commit d978cfae017194ffe79a37c69c7fc1befb727199
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Fix attempt to free uninitialised pointer.

diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index 56fd466..4a61177 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -205,7 +205,6 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
 
     if (line == NULL) {
       g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file when reading path\n"));
-      g_free (string);
       return NULL;
     }
 

commit e09936bfe0b2db080cab5376088f24656b0e2ad7
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Make sure attributes are stored internally in the same order as before, or
    else the gsymcheck tests will fail.

diff --git a/libgeda/src/a_basic.c b/libgeda/src/a_basic.c
index 06c9381..9d8876e 100644
--- a/libgeda/src/a_basic.c
+++ b/libgeda/src/a_basic.c
@@ -407,7 +407,9 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
           new_attrs_list = o_read_attribs (toplevel, new_obj, tb, release_ver, fileformat_ver, err);
           if (new_attrs_list == NULL)
             goto error;
-          new_object_list = g_list_concat (new_object_list, new_attrs_list);
+
+	  new_attrs_list = g_list_reverse(new_attrs_list);
+          new_object_list = g_list_concat (new_attrs_list, new_object_list);
 
           /* by now we have finished reading all the attributes */
           /* did we just finish attaching to a complex object? */

commit 206b5f430917287d4d1d46acd5af32ab8ea34877
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Updated error messages in o_picture_read, o_path_read, and o_text_read to
    follow style of other similar error messages.

diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index 0af5814..56fd466 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -204,7 +204,7 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
     line = s_textbuffer_next_line (tb);
 
     if (line == NULL) {
-      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Premature eof when reading path\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file when reading path\n"));
       g_free (string);
       return NULL;
     }
diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index bfedfc4..ef958ac 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -69,8 +69,7 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
 	 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
   
   if (num_conv != 8) {
-    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Error reading picture definition line: %s.\n"),
-                                              first_line);
+    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse picture definition\n"));
     return NULL;
   }
 
diff --git a/libgeda/src/o_text_basic.c b/libgeda/src/o_text_basic.c
index 0c2b6c0..4f493d0 100644
--- a/libgeda/src/o_text_basic.c
+++ b/libgeda/src/o_text_basic.c
@@ -437,7 +437,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 
     if (line == NULL) {
       g_string_free (textstr, TRUE);
-      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Premature end of data after %d lines\n"), i);
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file after %d lines\n"), i);
       return NULL;
     }
 

commit 46ffae4667dda3520b31b92370dcafe1e24017a0
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Made edascm_string_format_sym local.

diff --git a/libgeda/include/libgedaguile_priv.h b/libgeda/include/libgedaguile_priv.h
index 1ef553a..229119b 100644
--- a/libgeda/include/libgedaguile_priv.h
+++ b/libgeda/include/libgedaguile_priv.h
@@ -136,4 +136,3 @@ extern inline void o_page_changed (TOPLEVEL *t, OBJECT *o);
 /* ---------------------------------------- */
 
 extern SCM edascm_object_state_sym;
-extern SCM edascm_string_format_sym;
diff --git a/libgeda/src/scheme_init.c b/libgeda/src/scheme_init.c
index 1268ce6..a9da63e 100644
--- a/libgeda/src/scheme_init.c
+++ b/libgeda/src/scheme_init.c
@@ -30,7 +30,6 @@
 static int init_called = 0;
 
 SCM_GLOBAL_SYMBOL (edascm_object_state_sym, "object-state");
-SCM_GLOBAL_SYMBOL (edascm_string_format_sym , "string-format");
 
 /*! \brief Initialise the Scheme API.
  * \par Function Description
diff --git a/libgeda/src/scheme_page.c b/libgeda/src/scheme_page.c
index 0f63dba..c647653 100644
--- a/libgeda/src/scheme_page.c
+++ b/libgeda/src/scheme_page.c
@@ -27,6 +27,8 @@
 #include "libgeda_priv.h"
 #include "libgedaguile_priv.h"
 
+SCM_SYMBOL (edascm_string_format_sym , "string-format");
+
 /*! \brief Get a of open pages.
  * \par Function Description
  * Retrieves a Scheme list of currently-opened pages.

commit 3ffd19131319cd74689dcb388e53cf12948c26d5
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Updated unit tests for scheme api (string->page function).

diff --git a/libgeda/scheme/Makefile.am b/libgeda/scheme/Makefile.am
index eb6c3fd..5dddadf 100644
--- a/libgeda/scheme/Makefile.am
+++ b/libgeda/scheme/Makefile.am
@@ -36,7 +36,6 @@ TESTS = unit-tests/t0001-geda-conf-lib.scm \
 	unit-tests/t1000-deprecated.scm
 
 XFAIL_TESTS = \
-	unit-tests/t0203-page-string-syntax.scm \
 	unit-tests/t0301-promotable-attributes.scm
 
 dist_noinst_DATA = geda/core/gettext.scm.in unit-test.scm $(TESTS)
diff --git a/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm b/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
index c05432a..407005b 100644
--- a/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
+++ b/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
@@ -5,7 +5,5 @@
 (use-modules (geda page))
 (use-modules (geda object))
 
-;; string->page should bork if the string contains invalid syntax.  It
-;; might not throw a misc-error; this is just a placeholder key.
 (begin-test 'string->page
   (assert-thrown 'string-format (string->page "/test/page/A" "__GARBAGE__")))

commit 7fa7d9ec42e089fcba9f2876c45330c406b19891
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Use an "Ok" button instead of "Close" button for dialog box if
    parsing data from clipboard fails.

diff --git a/gschem/src/x_clipboard.c b/gschem/src/x_clipboard.c
index 27e6e70..b9fb922 100644
--- a/gschem/src/x_clipboard.c
+++ b/gschem/src/x_clipboard.c
@@ -244,7 +244,7 @@ x_clipboard_get (GSCHEM_TOPLEVEL *w_current)
      GtkWidget * dialog = gtk_message_dialog_new (w_current->main_window,
                                       GTK_DIALOG_DESTROY_WITH_PARENT,
                                       GTK_MESSAGE_ERROR,
-                                      GTK_BUTTONS_CLOSE,
+                                      GTK_BUTTONS_OK,
                                       _("Invalid schematic on clipboard: %s"),
                                       err->message);
 

commit 5d69c79dbc7be5516cd87d47765a63bdb2dcdd33
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Renamed exception invalid-string to string-format in documentation.

diff --git a/docs/scheme-api/geda-scheme.texi b/docs/scheme-api/geda-scheme.texi
index 4bcba6e..7917204 100644
--- a/docs/scheme-api/geda-scheme.texi
+++ b/docs/scheme-api/geda-scheme.texi
@@ -400,7 +400,7 @@ Parses @var{string}, which should be in the gEDA file format, to
 create a new @code{page}.  The initial filename for the new
 @code{page} is @var{filename}.
 
-If the string is not in gEDA format, raises an @code{invalid-string} error.
+If the string is not in gEDA format, raises an @code{string-format} error.
 @end defun
 
 @defun page->string page

commit 64a7d0283c3c15e1b27077ee5a9c1ec209c0a807
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Rebase fixes for o_picture.c.

diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index 1066498..bfedfc4 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -150,46 +150,6 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
       embedded = 0;
     }
   }
-
-  /* If we have embedded data, try loading from the decoded buffer */
-  if (file_content != NULL) {
-    pixbuf = o_picture_pixbuf_from_buffer (file_content, file_length, err);
-    if (err != NULL) {
-      s_log_message (_("Failed to load image from embedded data [%s]: %s\n"),
-                     filename, *err->message);
-      s_log_message (_("Falling back to file loading. Picture unembedded.\n"));
-      g_error_free (err);
-      *err = NULL;
-      embedded = 0;
-    }
-  }
-
-  /* If we haven't loaded the pixbuf above, try loading from file */
-  if (pixbuf == NULL) {
-    pixbuf = gdk_pixbuf_new_from_file (filename, err);
-    if (*err != NULL) {
-      s_log_message (_("Failed to load image from file [%s]: %s\n"),
-                     filename, *err->message);
-      g_error_free (*err);
-      *err = NULL;
-    }
-  }
-
-  /* If the pixbuf couldn't be loaded, then try to load a warning picture */
-  if (pixbuf == NULL) {
-    char *temp_filename;
-
-    s_log_message (_("Loading warning picture.\n"));
-    
-    temp_filename = g_build_filename (toplevel->bitmap_directory,
-                                      "gschem-warning.png", NULL);
-    pixbuf = gdk_pixbuf_new_from_file (temp_filename, NULL);
-    if (pixbuf == NULL) {
-      s_log_message( _("Error loading picture from file: %s.\n"),
-                     temp_filename);
-    }      
-    g_free (temp_filename);
-  }
   
   /* create the picture */
   /* The picture is described by its upper left and lower right corner */
@@ -204,7 +164,6 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
   return new_obj;
 }
 
-
 /*! \brief Create a character string representation of a picture OBJECT.
  *  \par Function Description
  *  This function formats a string in the buffer <B>*buff</B> to describe

commit 2b025def49c1bfeedb0650b4c34d527fa29a5090
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Changed invalid-string -> string-format

diff --git a/libgeda/include/libgedaguile_priv.h b/libgeda/include/libgedaguile_priv.h
index 95aa157..1ef553a 100644
--- a/libgeda/include/libgedaguile_priv.h
+++ b/libgeda/include/libgedaguile_priv.h
@@ -136,4 +136,4 @@ extern inline void o_page_changed (TOPLEVEL *t, OBJECT *o);
 /* ---------------------------------------- */
 
 extern SCM edascm_object_state_sym;
-extern SCM edascm_invalid_string_sym;
+extern SCM edascm_string_format_sym;
diff --git a/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm b/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
index 657d680..c05432a 100644
--- a/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
+++ b/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
@@ -8,4 +8,4 @@
 ;; string->page should bork if the string contains invalid syntax.  It
 ;; might not throw a misc-error; this is just a placeholder key.
 (begin-test 'string->page
-  (assert-thrown 'invalid-string (string->page "/test/page/A" "__GARBAGE__")))
+  (assert-thrown 'string-format (string->page "/test/page/A" "__GARBAGE__")))
diff --git a/libgeda/src/scheme_init.c b/libgeda/src/scheme_init.c
index 9fa7d51..1268ce6 100644
--- a/libgeda/src/scheme_init.c
+++ b/libgeda/src/scheme_init.c
@@ -30,7 +30,7 @@
 static int init_called = 0;
 
 SCM_GLOBAL_SYMBOL (edascm_object_state_sym, "object-state");
-SCM_GLOBAL_SYMBOL (edascm_invalid_string_sym , "invalid-string");
+SCM_GLOBAL_SYMBOL (edascm_string_format_sym , "string-format");
 
 /*! \brief Initialise the Scheme API.
  * \par Function Description
diff --git a/libgeda/src/scheme_page.c b/libgeda/src/scheme_page.c
index e2f1c2d..0f63dba 100644
--- a/libgeda/src/scheme_page.c
+++ b/libgeda/src/scheme_page.c
@@ -436,8 +436,8 @@ SCM_DEFINE (string_to_page, "%string->page", 2, 0, 0,
       SCM error_message = scm_from_utf8_string (err->message);
 
       g_error_free(err);
-      scm_error (edascm_invalid_string_sym, s_string_to_page,
-                 _("Invalid string: ~s"), scm_list_1 (error_message), SCM_EOL);
+      scm_error (edascm_string_format_sym, s_string_to_page,
+                 _("Parse error: ~s"), scm_list_1 (error_message), SCM_EOL);
   }
 
   s_page_append_list (toplevel, page, objects);

commit b0541a1258d82b40b7b604a15d177780fd1b7cf9
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Changed enum EDA_ERROR_READ -> EDA_ERROR_PARSE, and made replaced G_FILE_ERROR_FAILED by
    EDA_ERROR_READ in appropriate places.

diff --git a/libgeda/include/libgeda/edaerrors.h b/libgeda/include/libgeda/edaerrors.h
index 2b50513..4fe4e0e 100644
--- a/libgeda/include/libgeda/edaerrors.h
+++ b/libgeda/include/libgeda/edaerrors.h
@@ -27,7 +27,7 @@ typedef enum {
   EDA_ERROR_SCHEME,   /* A Scheme error occurred */
   EDA_ERROR_RC_TWICE, /* Attempted to read a configuration file twice */
   EDA_ERROR_NUM_ERRORS,
-  EDA_ERROR_READ,
+  EDA_ERROR_PARSE,
 } EdaError;
 
 GQuark eda_error_quark (void);
diff --git a/libgeda/src/a_basic.c b/libgeda/src/a_basic.c
index aedbba9..06c9381 100644
--- a/libgeda/src/a_basic.c
+++ b/libgeda/src/a_basic.c
@@ -428,7 +428,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
           new_obj = NULL;
         }
         else {
-          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read unexpected attach "
+          g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read unexpected attach "
                                                                  "symbol start marker in [%s] :\n>>\n%s<<\n"),
                        name, line);
           goto error;
@@ -447,7 +447,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
 
           embedded_level++;
         } else {
-          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read unexpected embedded "
+          g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read unexpected embedded "
                                                                  "symbol start marker in [%s] :\n>>\n%s<<\n"),
                        name, line);
           goto error;
@@ -478,7 +478,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
 
           embedded_level--;
         } else {
-          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read unexpected embedded "
+          g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read unexpected embedded "
                                                                  "symbol end marker in [%s] :\n>>\n%s<<\n"),
                        name, line);
           goto error;
@@ -501,7 +501,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
         itemsread = sscanf(line, "v %u %u\n", &release_ver, &fileformat_ver);
 
         if (itemsread == 0) {
-          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Failed to parse version from buffer.\n");
+          g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, "Failed to parse version from buffer.\n");
           goto error;
         }
 
@@ -519,7 +519,7 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
         break;
 
       default:
-        g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read garbage in [%s] :\n>>\n%s<<\n"), name, line);
+        g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read garbage in [%s] :\n>>\n%s<<\n"), name, line);
         new_obj = NULL;
         goto error;
     }
diff --git a/libgeda/src/o_arc_basic.c b/libgeda/src/o_arc_basic.c
index 9a20f43..c25e2b5 100644
--- a/libgeda/src/o_arc_basic.c
+++ b/libgeda/src/o_arc_basic.c
@@ -253,7 +253,7 @@ OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[],
   if(release_ver <= VERSION_20000704) {
     if (sscanf(buf, "%c %d %d %d %d %d %d", &type,
 	       &x1, &y1, &radius, &start_angle, &end_angle, &color) != 7) {
-      g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to parse arc object\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object\n"));
       return NULL;
     }
 
@@ -266,7 +266,7 @@ OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[],
     if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d", &type,
 	       &x1, &y1, &radius, &start_angle, &end_angle, &color,
 	       &arc_width, &arc_end, &arc_type, &arc_length, &arc_space) != 12) {
-      g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to parse arc object\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object\n"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_attrib.c b/libgeda/src/o_attrib.c
index 93da42c..5f1a9ee 100644
--- a/libgeda/src/o_attrib.c
+++ b/libgeda/src/o_attrib.c
@@ -332,7 +332,7 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
       o_attrib_attach (toplevel, new_obj, object_to_get_attribs, FALSE);
       ATTACH=FALSE;
     } else {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Tried to attach a non-text item as an attribute\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Tried to attach a non-text item as an attribute\n"));
       goto error;
     }
   }
diff --git a/libgeda/src/o_box_basic.c b/libgeda/src/o_box_basic.c
index 66b97fe..22f21cd 100644
--- a/libgeda/src/o_box_basic.c
+++ b/libgeda/src/o_box_basic.c
@@ -284,7 +284,7 @@ OBJECT *o_box_read (TOPLEVEL *toplevel, char buf[],
 
     if (sscanf (buf, "%c %d %d %d %d %d\n",
 		&type, &x1, &y1, &width, &height, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse box object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object\n"));
       return NULL;
     }
 
@@ -313,7 +313,7 @@ OBJECT *o_box_read (TOPLEVEL *toplevel, char buf[],
 		&box_width, &box_end, &box_type, &box_length,
 		&box_space, &box_filling,
 		&fill_width, &angle1, &pitch1, &angle2, &pitch2) != 17) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse box object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object\n"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_bus_basic.c b/libgeda/src/o_bus_basic.c
index c87c01c..0222daf 100644
--- a/libgeda/src/o_bus_basic.c
+++ b/libgeda/src/o_bus_basic.c
@@ -157,14 +157,14 @@ OBJECT *o_bus_read (TOPLEVEL *toplevel, char buf[],
 
   if (release_ver <= VERSION_20020825) {
     if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse bus object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object\n"));
       return NULL;
     }
     ripper_dir = 0;
   } else {
     if (sscanf (buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color,
 		&ripper_dir) != 7) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse bus object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object\n"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_circle_basic.c b/libgeda/src/o_circle_basic.c
index da43b73..98b08a3 100644
--- a/libgeda/src/o_circle_basic.c
+++ b/libgeda/src/o_circle_basic.c
@@ -243,7 +243,7 @@ OBJECT *o_circle_read (TOPLEVEL *toplevel, char buf[],
      * to default.
      */
     if (sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color) != 5) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse circle object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object\n"));
       return NULL;
     }
 
@@ -272,7 +272,7 @@ OBJECT *o_circle_read (TOPLEVEL *toplevel, char buf[],
 	       &circle_width, &circle_end, &circle_type,
 	       &circle_length, &circle_space, &circle_fill,
 	       &fill_width, &angle1, &pitch1, &angle2, &pitch2) != 16) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse circle object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object\n"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_complex_basic.c b/libgeda/src/o_complex_basic.c
index 88ad6d0..6a92272 100644
--- a/libgeda/src/o_complex_basic.c
+++ b/libgeda/src/o_complex_basic.c
@@ -651,7 +651,7 @@ OBJECT *o_complex_read (TOPLEVEL *toplevel,
 
   if (sscanf(buf, "%c %d %d %d %d %d %s\n",
 	     &type, &x1, &y1, &selectable, &angle, &mirror, basename) != 7) {
-    g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse complex object\n"));
+    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse complex object\n"));
     return NULL;
   }
 
diff --git a/libgeda/src/o_line_basic.c b/libgeda/src/o_line_basic.c
index 19fb3b7..db841cf 100644
--- a/libgeda/src/o_line_basic.c
+++ b/libgeda/src/o_line_basic.c
@@ -226,7 +226,7 @@ OBJECT *o_line_read (TOPLEVEL *toplevel, char buf[],
      */
     if (sscanf (buf, "%c %d %d %d %d %d\n", &type,
 		&x1, &y1, &x2, &y2, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse line object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse line object\n"));
       return NULL;
     }
 
@@ -244,7 +244,7 @@ OBJECT *o_line_read (TOPLEVEL *toplevel, char buf[],
       if (sscanf (buf, "%c %d %d %d %d %d %d %d %d %d %d\n", &type,
 		  &x1, &y1, &x2, &y2, &color,
 		  &line_width, &line_end, &line_type, &line_length, &line_space) != 11) {
-        g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse line object\n"));
+        g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse line object\n"));
         return NULL;
       }
   }
diff --git a/libgeda/src/o_net_basic.c b/libgeda/src/o_net_basic.c
index 3ae39fa..5d0d855 100644
--- a/libgeda/src/o_net_basic.c
+++ b/libgeda/src/o_net_basic.c
@@ -153,7 +153,7 @@ OBJECT *o_net_read (TOPLEVEL *toplevel, char buf[],
   int color;
 
   if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
-        g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse net object\n"));
+        g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse net object\n"));
     return NULL;
   }
 
diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index 8a7f2d1..0af5814 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -178,7 +178,7 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
 	      &type, &color, &line_width, &line_end, &line_type,
 	      &line_length, &line_space, &fill_type, &fill_width, &angle1,
 	      &pitch1, &angle2, &pitch2, &num_lines) != 14) {
-    g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse path object\n"));
+    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse path object\n"));
     return NULL;
   }
 
@@ -204,7 +204,7 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
     line = s_textbuffer_next_line (tb);
 
     if (line == NULL) {
-      g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Premature eof when reading path\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Premature eof when reading path\n"));
       g_free (string);
       return NULL;
     }
diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index e8e4d01..1066498 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -69,7 +69,7 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
 	 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
   
   if (num_conv != 8) {
-    g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Error reading picture definition line: %s.\n"),
+    g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Error reading picture definition line: %s.\n"),
                                               first_line);
     return NULL;
   }
diff --git a/libgeda/src/o_pin_basic.c b/libgeda/src/o_pin_basic.c
index 8186b08..377bdc1 100644
--- a/libgeda/src/o_pin_basic.c
+++ b/libgeda/src/o_pin_basic.c
@@ -157,7 +157,7 @@ OBJECT *o_pin_read (TOPLEVEL *toplevel, char buf[],
 
   if (release_ver <= VERSION_20020825) {
     if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse pin object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object\n"));
       return NULL;
     }
     pin_type = PIN_TYPE_NET;
@@ -165,7 +165,7 @@ OBJECT *o_pin_read (TOPLEVEL *toplevel, char buf[],
   } else {
     if (sscanf (buf, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2,
 		&color, &pin_type, &whichend) != 8) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse pin object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object\n"));
       return NULL;
     }
   }
diff --git a/libgeda/src/o_text_basic.c b/libgeda/src/o_text_basic.c
index 664c9c2..0c2b6c0 100644
--- a/libgeda/src/o_text_basic.c
+++ b/libgeda/src/o_text_basic.c
@@ -353,7 +353,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 	       &color, &size,
 	       &visibility, &show_name_value, 
 	       &angle, &alignment, &num_lines) != 10) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse text object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object\n"));
       return NULL;
     }
   } else if (release_ver < VERSION_20000220) {
@@ -363,7 +363,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 	       &color, &size,
 	       &visibility, &show_name_value, 
 	       &angle) != 8) {
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse text object\n"));
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object\n"));
       return NULL;
     }
     alignment = LOWER_LEFT; /* older versions didn't have this */
@@ -373,7 +373,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 	       &color, &size,
 	       &visibility, &show_name_value, 
            &angle, &alignment) != 9) {
-      g_set_error (err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse text object\n"));
+      g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object\n"));
       return NULL;
     }
     num_lines = 1; /* only support a single line */
@@ -437,7 +437,7 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
 
     if (line == NULL) {
       g_string_free (textstr, TRUE);
-      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Premature end of data after %d lines\n"), i);
+      g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Premature end of data after %d lines\n"), i);
       return NULL;
     }
 

commit 8c4438ef6071fede03c687c317a1f9d1489dd5f4
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Improved error reporting/behaviour when a symbol cannot be loaded.

diff --git a/gschem/src/o_complex.c b/gschem/src/o_complex.c
index 56f9981..8f4853c 100644
--- a/gschem/src/o_complex.c
+++ b/gschem/src/o_complex.c
@@ -94,11 +94,19 @@ void o_complex_prepare_place(GSCHEM_TOPLEVEL *w_current, const CLibSymbol *sym)
                                buffer, -1,
                                sym_name,
                                &err);
-    // FIXME: How can we improve the error handling here? Currently err is ignored.
-    if (err)
-        g_error_free(err);
     g_free (buffer);
 
+    if (err) {
+      /* If an error occurs here, we can assume that the preview also has failed to load,
+         and the error message is displayed there. We therefore ignore this error, but
+         end the component insertion.
+         */
+
+      g_error_free(err);
+      i_set_state (w_current, SELECT);
+      return;
+    }
+
     /* Take the added objects */
     toplevel->page_current->place_list =
       g_list_concat (toplevel->page_current->place_list, temp_list);
@@ -109,16 +117,26 @@ void o_complex_prepare_place(GSCHEM_TOPLEVEL *w_current, const CLibSymbol *sym)
     new_object = o_complex_new (toplevel, OBJ_COMPLEX, DEFAULT_COLOR,
                                 0, 0, 0, 0, sym, sym_name, 1);
 
-    toplevel->page_current->place_list =
-      g_list_concat (toplevel->page_current->place_list,
-        o_complex_promote_attribs (toplevel, new_object));
-    toplevel->page_current->place_list =
-      g_list_append (toplevel->page_current->place_list, new_object);
+    if (new_object->type == OBJ_PLACEHOLDER) {
+      /* If created object is a placeholder, the loading failed and we end the insert action */
 
-    /* Flag the symbol as embedded if necessary */
-    o_current = (g_list_last (toplevel->page_current->place_list))->data;
-    if (w_current->embed_complex) {
-      o_current->complex_embedded = TRUE;
+      s_delete_object(toplevel, new_object);
+      i_set_state (w_current, SELECT);
+      return;
+    }
+    else {
+
+      toplevel->page_current->place_list =
+          g_list_concat (toplevel->page_current->place_list,
+                         o_complex_promote_attribs (toplevel, new_object));
+      toplevel->page_current->place_list =
+          g_list_append (toplevel->page_current->place_list, new_object);
+
+      /* Flag the symbol as embedded if necessary */
+      o_current = (g_list_last (toplevel->page_current->place_list))->data;
+      if (w_current->embed_complex) {
+        o_current->complex_embedded = TRUE;
+      }
     }
   }
 
diff --git a/gschem/src/x_preview.c b/gschem/src/x_preview.c
index 810366b..63206a0 100644
--- a/gschem/src/x_preview.c
+++ b/gschem/src/x_preview.c
@@ -60,7 +60,6 @@ static void preview_get_property (GObject *object,
                                   GParamSpec *pspec);
 static void preview_dispose (GObject *self);
 
-
 /*! \brief Completes initialitation of the widget after realization.
  *  \par Function Description
  *  This function terminates the initialization of preview's GSCHEM_TOPLEVEL
@@ -226,18 +225,20 @@ preview_update (Preview *preview)
       /* we should display something if there an error occured - Fix me */
     }
     if (preview->buffer != NULL) {
-
       /* Load the data buffer */
-      s_page_append_list (preview_toplevel, preview_toplevel->page_current,
-                          o_read_buffer (preview_toplevel,
-                                         NULL, preview->buffer, -1,
-                                         _("Preview Buffer"), &err));
-      if (err) {
-          char * msg = g_strdup_printf(_("Invalid schematic: %s"), err->message);
-
-          generic_msg_dialog(msg);
-          g_free(msg);
-          g_error_free(err);
+      GList * objects = o_read_buffer (preview_toplevel,
+                                       NULL, preview->buffer, -1,
+                                       _("Preview Buffer"), &err);
+
+      if (err == NULL) {
+        s_page_append_list (preview_toplevel, preview_toplevel->page_current,
+                            objects);
+      }
+      else {
+        s_page_append (preview_toplevel, preview_toplevel->page_current,
+                       o_text_new(preview_toplevel, OBJ_TEXT, 2, 100, 100, LOWER_MIDDLE, 0,
+                                  err->message, 10, VISIBLE, SHOW_NAME_VALUE));
+        g_error_free(err);
       }
     }
   }

commit 4cebffe4ffc464cc16ac08191083deb0cbc76bbc
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Use GtkMeessageDialog instead of the generic dialog.

diff --git a/gschem/src/x_clipboard.c b/gschem/src/x_clipboard.c
index 48a8c76..27e6e70 100644
--- a/gschem/src/x_clipboard.c
+++ b/gschem/src/x_clipboard.c
@@ -241,10 +241,15 @@ x_clipboard_get (GSCHEM_TOPLEVEL *w_current)
                                (gchar *) buf, -1, "Clipboard", &err);
 
   if (err) {
-     char * msg = g_strdup_printf(_("Invalid schematic on clipboard: %s"), err->message);
-
-     generic_msg_dialog(msg);
-     g_free(msg);
+     GtkWidget * dialog = gtk_message_dialog_new (w_current->main_window,
+                                      GTK_DIALOG_DESTROY_WITH_PARENT,
+                                      GTK_MESSAGE_ERROR,
+                                      GTK_BUTTONS_CLOSE,
+                                      _("Invalid schematic on clipboard: %s"),
+                                      err->message);
+
+     gtk_dialog_run (GTK_DIALOG (dialog));
+     gtk_widget_destroy (dialog);
      g_error_free(err);
   }
   gtk_selection_data_free (selection_data);

commit 09bd3be24aff7139ca4c8d3dc99f520c873a8b2d
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Fixed missing end of function.

diff --git a/docs/scheme-api/geda-scheme.texi b/docs/scheme-api/geda-scheme.texi
index e4a6072..4bcba6e 100644
--- a/docs/scheme-api/geda-scheme.texi
+++ b/docs/scheme-api/geda-scheme.texi
@@ -401,6 +401,7 @@ create a new @code{page}.  The initial filename for the new
 @code{page} is @var{filename}.
 
 If the string is not in gEDA format, raises an @code{invalid-string} error.
+@end defun
 
 @defun page->string page
 Returns a string representation of @var{page} in the gEDA file

commit d1305adf92982b3a159707c940bafb8c293223fe
Author: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>
Commit: Eivind Kvedalen <eivind@xxxxxxxxxxxxx>

    Partial fix for bug #700448.
    
    NULL is returned from o_*_read and o_read_buffer functions if parsing of the input buffer fails.
    An error object is returned in these cases, describing in detail what error occured.
    
    gnetlist is updated to exit with status code 2 if the input file can't be read.
    
    gschem is updated to report errors when using o_read_buffer.
    
    TODO:
    * Prone to segfaults on bad input files (separate patch)

diff --git a/docs/scheme-api/geda-scheme.texi b/docs/scheme-api/geda-scheme.texi
index f7b251c..e4a6072 100644
--- a/docs/scheme-api/geda-scheme.texi
+++ b/docs/scheme-api/geda-scheme.texi
@@ -400,10 +400,7 @@ Parses @var{string}, which should be in the gEDA file format, to
 create a new @code{page}.  The initial filename for the new
 @code{page} is @var{filename}.
 
-@strong{Warning}: Due to missing functionality in the underlying C
-library, this @code{string->page} cannot currently report invalid
-syntax or other problems in the @var{string} passed.
-@end defun
+If the string is not in gEDA format, raises an @code{invalid-string} error.
 
 @defun page->string page
 Returns a string representation of @var{page} in the gEDA file
diff --git a/gnetlist/src/gnetlist.c b/gnetlist/src/gnetlist.c
index 4d7120c..d674bfb 100644
--- a/gnetlist/src/gnetlist.c
+++ b/gnetlist/src/gnetlist.c
@@ -232,6 +232,7 @@ void main_prog(void *closure, int argc, char *argv[])
         g_warning ("%s\n", err->message);
         fprintf (stderr, "%s\n", err->message);
         g_error_free (err);
+	exit(2);
       }
 
       /* collect input filenames for backend use */
diff --git a/gschem/src/o_complex.c b/gschem/src/o_complex.c
index 6b692fc..56f9981 100644
--- a/gschem/src/o_complex.c
+++ b/gschem/src/o_complex.c
@@ -72,6 +72,7 @@ void o_complex_prepare_place(GSCHEM_TOPLEVEL *w_current, const CLibSymbol *sym)
   OBJECT *o_current;
   char *buffer;
   const gchar *sym_name = s_clib_symbol_get_name (sym);
+  GError *err = NULL;
 
   /* remove the old place list if it exists */
   s_delete_object_glist(toplevel, toplevel->page_current->place_list);
@@ -91,7 +92,11 @@ void o_complex_prepare_place(GSCHEM_TOPLEVEL *w_current, const CLibSymbol *sym)
     temp_list = o_read_buffer (toplevel,
                                temp_list,
                                buffer, -1,
-                               sym_name);
+                               sym_name,
+                               &err);
+    // FIXME: How can we improve the error handling here? Currently err is ignored.
+    if (err)
+        g_error_free(err);
     g_free (buffer);
 
     /* Take the added objects */
diff --git a/gschem/src/x_clipboard.c b/gschem/src/x_clipboard.c
index d89018c..48a8c76 100644
--- a/gschem/src/x_clipboard.c
+++ b/gschem/src/x_clipboard.c
@@ -224,6 +224,7 @@ x_clipboard_get (GSCHEM_TOPLEVEL *w_current)
   GtkSelectionData *selection_data;
   GList *object_list = NULL;
   const guchar *buf;
+  GError * err = NULL;
 
   /* Try to get the contents of the clipboard */
   selection_data = gtk_clipboard_wait_for_contents (cb, type);
@@ -237,8 +238,15 @@ x_clipboard_get (GSCHEM_TOPLEVEL *w_current)
 #endif
 
   object_list = o_read_buffer (toplevel, object_list,
-                               (gchar *) buf, -1, "Clipboard");
+                               (gchar *) buf, -1, "Clipboard", &err);
 
+  if (err) {
+     char * msg = g_strdup_printf(_("Invalid schematic on clipboard: %s"), err->message);
+
+     generic_msg_dialog(msg);
+     g_free(msg);
+     g_error_free(err);
+  }
   gtk_selection_data_free (selection_data);
   return object_list;
 }
diff --git a/gschem/src/x_preview.c b/gschem/src/x_preview.c
index be76d64..810366b 100644
--- a/gschem/src/x_preview.c
+++ b/gschem/src/x_preview.c
@@ -204,6 +204,7 @@ preview_update (Preview *preview)
   TOPLEVEL *preview_toplevel = preview_w_current->toplevel;
   int left, top, right, bottom;
   int width, height;
+  GError * err = NULL;
 
   if (preview_toplevel->page_current == NULL) {
     return;
@@ -230,7 +231,14 @@ preview_update (Preview *preview)
       s_page_append_list (preview_toplevel, preview_toplevel->page_current,
                           o_read_buffer (preview_toplevel,
                                          NULL, preview->buffer, -1,
-                                         _("Preview Buffer")));
+                                         _("Preview Buffer"), &err));
+      if (err) {
+          char * msg = g_strdup_printf(_("Invalid schematic: %s"), err->message);
+
+          generic_msg_dialog(msg);
+          g_free(msg);
+          g_error_free(err);
+      }
     }
   }
 
diff --git a/libgeda/include/libgeda/edaerrors.h b/libgeda/include/libgeda/edaerrors.h
index ce7f002..2b50513 100644
--- a/libgeda/include/libgeda/edaerrors.h
+++ b/libgeda/include/libgeda/edaerrors.h
@@ -27,6 +27,7 @@ typedef enum {
   EDA_ERROR_SCHEME,   /* A Scheme error occurred */
   EDA_ERROR_RC_TWICE, /* Attempted to read a configuration file twice */
   EDA_ERROR_NUM_ERRORS,
+  EDA_ERROR_READ,
 } EdaError;
 
 GQuark eda_error_quark (void);
diff --git a/libgeda/include/libgeda/prototype.h b/libgeda/include/libgeda/prototype.h
index 9e9f0bc..56a6cdc 100644
--- a/libgeda/include/libgeda/prototype.h
+++ b/libgeda/include/libgeda/prototype.h
@@ -4,7 +4,7 @@ G_BEGIN_DECLS
 const gchar *o_file_format_header();
 gchar *o_save_buffer (TOPLEVEL *toplevel, const GList *object_list);
 int o_save (TOPLEVEL *toplevel, const GList *object_list, const char *filename, GError **err);
-GList *o_read_buffer(TOPLEVEL *toplevel, GList *object_list, char *buffer, const int size, const char *name);
+GList *o_read_buffer(TOPLEVEL *toplevel, GList *object_list, char *buffer, const int size, const char *name, GError **err);
 GList *o_read(TOPLEVEL *toplevel, GList *object_list, char *filename, GError **err);
 void o_scale(TOPLEVEL *toplevel, GList *list, int x_scale, int y_scale);
 
diff --git a/libgeda/include/libgedaguile_priv.h b/libgeda/include/libgedaguile_priv.h
index 229119b..95aa157 100644
--- a/libgeda/include/libgedaguile_priv.h
+++ b/libgeda/include/libgedaguile_priv.h
@@ -136,3 +136,4 @@ extern inline void o_page_changed (TOPLEVEL *t, OBJECT *o);
 /* ---------------------------------------- */
 
 extern SCM edascm_object_state_sym;
+extern SCM edascm_invalid_string_sym;
diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index 927f672..26fbd90 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -70,7 +70,7 @@ void m_transform_scale(TRANSFORM *transform, gdouble factor);
 void m_transform_translate(TRANSFORM *transform, gdouble dx, gdouble dy);
 
 /* o_arc_basic.c */
-OBJECT *o_arc_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_arc_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_arc_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_arc_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_arc_print_solid(TOPLEVEL *toplevel, FILE *fp, int x, int y, int radius, int angle1, int angle2, int color, int arc_width, int length, int space, int origin_x, int origin_y);
@@ -86,11 +86,10 @@ void o_arc_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_attrib.c */
 GList *o_read_attribs(TOPLEVEL *toplevel,
-                      GList *list,
                       OBJECT *object_to_get_attribs,
                       TextBuffer *tb,
                       unsigned int release_ver,
-                      unsigned int fileformat_ver);
+                      unsigned int fileformat_ver, GError **err);
 OBJECT *o_attrib_find_attrib_by_name(const GList *list, char *name, int count);
 
 /* o_basic.c */
@@ -101,7 +100,7 @@ void o_emit_pre_change_notify(TOPLEVEL *toplevel, OBJECT *object);
 void o_emit_change_notify(TOPLEVEL *toplevel, OBJECT *object);
 
 /* o_box_basic.c */
-OBJECT *o_box_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_box_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_box_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_box_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_box_print_solid(TOPLEVEL *toplevel, FILE *fp, int x, int y, int width, int height, int color, int line_width, int length, int space, int origin_x, int origin_y);
@@ -118,7 +117,7 @@ gboolean o_box_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object
 void o_box_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_bus_basic.c */
-OBJECT *o_bus_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_bus_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_bus_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_bus_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void world_get_bus_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top, int *right, int *bottom);
@@ -126,7 +125,7 @@ gboolean o_bus_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object
 void o_bus_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_circle_basic.c */
-OBJECT *o_circle_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_circle_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_circle_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_circle_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_circle_print_solid(TOPLEVEL *toplevel, FILE *fp, int x, int y, int radius, int color, int circle_width, int length, int space, int origin_x, int origin_y);
@@ -143,7 +142,7 @@ gboolean o_circle_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *obj
 void o_circle_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_complex_basic.c */
-OBJECT *o_complex_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_complex_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_complex_save(TOPLEVEL *toplevel, OBJECT *object);
 double o_complex_shortest_distance(OBJECT *object, int x, int y, int force_soild);
 void world_get_complex_bounds(TOPLEVEL *toplevel, OBJECT *complex, int *left, int *top, int *right, int *bottom);
@@ -152,7 +151,7 @@ void o_complex_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 GList *o_complex_get_promotable (TOPLEVEL *toplevel, OBJECT *object, int detach);
 
 /* o_line_basic.c */
-OBJECT *o_line_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_line_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_line_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_line_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void o_line_print_solid(TOPLEVEL *toplevel, FILE *fp, int x1, int y1, int x2, int y2, int color, int line_width, int length, int space, int origin_x, int origin_y);
@@ -166,7 +165,7 @@ gboolean o_line_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *objec
 void o_line_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_net_basic.c */
-OBJECT *o_net_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_net_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_net_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_net_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void world_get_net_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top, int *right, int *bottom);
@@ -174,7 +173,7 @@ gboolean o_net_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object
 void o_net_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_path_basic.c */
-OBJECT *o_path_read(TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_path_read(TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_path_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_path_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 double o_path_shortest_distance(OBJECT *object, int x, int y, int force_soild);
@@ -184,7 +183,7 @@ void o_path_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 
 /* o_picture.c */
-OBJECT *o_picture_read(TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_picture_read(TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_picture_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
 		     int origin_x, int origin_y);
@@ -196,7 +195,7 @@ void o_picture_embed(TOPLEVEL *toplevel, OBJECT *object);
 void o_picture_unembed(TOPLEVEL *toplevel, OBJECT *object);
 
 /* o_pin_basic.c */
-OBJECT *o_pin_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_pin_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_pin_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_pin_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y);
 void world_get_pin_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top, int *right, int *bottom);
@@ -204,7 +203,7 @@ gboolean o_pin_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object
 void o_pin_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
 
 /* o_text_basic.c */
-OBJECT *o_text_read(TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver);
+OBJECT *o_text_read(TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver, GError **err);
 char *o_text_save(TOPLEVEL *toplevel, OBJECT *object);
 void o_text_print_text_string(FILE *fp, char *string, int unicode_count, gunichar *unicode_table);
 void o_text_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, int origin_x, int origin_y, int unicode_count, gunichar *unicode_table);
diff --git a/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm b/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
index e608017..657d680 100644
--- a/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
+++ b/libgeda/scheme/unit-tests/t0203-page-string-syntax.scm
@@ -8,4 +8,4 @@
 ;; string->page should bork if the string contains invalid syntax.  It
 ;; might not throw a misc-error; this is just a placeholder key.
 (begin-test 'string->page
-  (assert-thrown 'misc-error (string->page "/test/page/A" "__GARBAGE__")))
+  (assert-thrown 'invalid-string (string->page "/test/page/A" "__GARBAGE__")))
diff --git a/libgeda/src/a_basic.c b/libgeda/src/a_basic.c
index 9be1f1b..aedbba9 100644
--- a/libgeda/src/a_basic.c
+++ b/libgeda/src/a_basic.c
@@ -268,7 +268,7 @@ int o_save (TOPLEVEL *toplevel, const GList *object_list,
  */
 GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
                       char *buffer, const int size,
-                      const char *name)
+                      const char *name, GError **err)
 {
   char *line = NULL;
   TextBuffer *tb = NULL;
@@ -276,7 +276,8 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
   char objtype;
   GList *object_list_save=NULL;
   OBJECT *new_obj=NULL;
-  GList *new_obj_list;
+  GList *new_attrs_list;
+  GList *new_object_list = NULL;
   GList *iter;
   unsigned int release_ver;
   unsigned int fileformat_ver;
@@ -295,8 +296,6 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
 
   tb = s_textbuffer_new (buffer, size);
 
-  object_list = g_list_reverse (object_list);
-
   while (1) {
 
     line = s_textbuffer_next_line(tb);
@@ -321,42 +320,50 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
     switch (objtype) {
 
       case(OBJ_LINE):
-        new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
 
       case(OBJ_NET):
-        new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_BUS):
-        new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_BOX):
-        new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_PICTURE):
         line = g_strdup (line);
-        new_obj = o_picture_read (toplevel, line, tb, release_ver, fileformat_ver);
+        new_obj = o_picture_read (toplevel, line, tb, release_ver, fileformat_ver, err);
         g_free (line);
-        object_list = g_list_prepend (object_list, new_obj);
+        if (new_obj == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_CIRCLE):
-        new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+	  goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_COMPLEX):
       case(OBJ_PLACEHOLDER):
-        new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
 
         /* last_complex is used for verifying symversion attribute */
         last_complex = new_obj;
@@ -364,71 +371,86 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
 
       case(OBJ_TEXT):
         line = g_strdup (line);
-        new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver);
+        new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err);
         g_free (line);
-        object_list = g_list_prepend (object_list, new_obj);
+        if (new_obj == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_PATH):
         line = g_strdup(line);
-        new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver);
+        new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err);
         g_free (line);
-        object_list = g_list_prepend (object_list, new_obj);
+        if (new_obj == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(OBJ_PIN):
-        new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         found_pin++;
         break;
 
       case(OBJ_ARC):
-        new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver);
-        object_list = g_list_prepend (object_list, new_obj);
+        if ((new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
+        new_object_list = g_list_prepend (new_object_list, new_obj);
         break;
 
       case(STARTATTACH_ATTR): 
         /* first is the fp */
         /* 2nd is the object to get the attributes */
-        new_obj_list = o_read_attribs (toplevel, NULL, new_obj, tb, release_ver, fileformat_ver);
-        new_obj_list = g_list_reverse (new_obj_list);
-        object_list = g_list_concat (new_obj_list, object_list);
-
-        /* by now we have finished reading all the attributes */
-        /* did we just finish attaching to a complex object? */
-        if (last_complex)
-        {
-          /* yes */
-          /* verify symbol version (not file format but rather contents) */
-          o_complex_check_symversion(toplevel, last_complex);
-          last_complex = NULL;
-        }
+        if (new_obj != NULL) {
+          new_attrs_list = o_read_attribs (toplevel, new_obj, tb, release_ver, fileformat_ver, err);
+          if (new_attrs_list == NULL)
+            goto error;
+          new_object_list = g_list_concat (new_object_list, new_attrs_list);
+
+          /* by now we have finished reading all the attributes */
+          /* did we just finish attaching to a complex object? */
+          if (last_complex)
+          {
+            /* yes */
+            /* verify symbol version (not file format but rather contents) */
+            o_complex_check_symversion(toplevel, last_complex);
+            last_complex = NULL;
+          }
 
-        /* slots only apply to complex objects */
-        if (new_obj != NULL &&
-            (new_obj->type == OBJ_COMPLEX ||
-             new_obj->type == OBJ_PLACEHOLDER)) {
-          s_slot_update_object (toplevel, new_obj);
+          /* slots only apply to complex objects */
+          if (new_obj != NULL &&
+              (new_obj->type == OBJ_COMPLEX ||
+               new_obj->type == OBJ_PLACEHOLDER)) {
+            s_slot_update_object (toplevel, new_obj);
+          }
+          new_obj = NULL;
+        }
+        else {
+          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read unexpected attach "
+                                                                 "symbol start marker in [%s] :\n>>\n%s<<\n"),
+                       name, line);
+          goto error;
         }
-
-        new_obj = NULL;
         break;
 
       case(START_EMBEDDED):
-        new_obj = object_list->data;
+        new_obj = new_object_list->data;
 
         if (new_obj != NULL &&
             (new_obj->type == OBJ_COMPLEX ||
              new_obj->type == OBJ_PLACEHOLDER)) {
 
-          object_list_save = object_list;
-          object_list = new_obj->complex->prim_objs;
+          object_list_save = new_object_list;
+          new_object_list = new_obj->complex->prim_objs;
 
           embedded_level++;
         } else {
-          fprintf(stderr, _("Read unexpected embedded "
-                            "symbol start marker in [%s] :\n>>\n%s<<\n"),
-                          name, line);
+          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read unexpected embedded "
+                                                                 "symbol start marker in [%s] :\n>>\n%s<<\n"),
+                       name, line);
+          goto error;
         }
         break;
 
@@ -436,14 +458,14 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
         if (embedded_level>0) {
           /* don't do this since objects are already
            * stored/read translated
-           * o_complex_translate_world (toplevel, object_list->x,
-           *                            object_list->y, object_list->complex);
+           * o_complex_translate_world (toplevel, new_object_list->x,
+           *                            new_object_list->y, new_object_list->complex);
            */
-          object_list = g_list_reverse (object_list);
+          new_object_list = g_list_reverse (new_object_list);
 
           new_obj = object_list_save->data;
-          new_obj->complex->prim_objs = object_list;
-          object_list = object_list_save;
+          new_obj->complex->prim_objs = new_object_list;
+          new_object_list = object_list_save;
 
           /* set the parent field now */
           for (iter = new_obj->complex->prim_objs;
@@ -456,9 +478,10 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
 
           embedded_level--;
         } else {
-          fprintf(stderr, _("Read unexpected embedded "
-                            "symbol end marker in [%s] :\n>>\n%s<<\n"),
-                          name, line);
+          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read unexpected embedded "
+                                                                 "symbol end marker in [%s] :\n>>\n%s<<\n"),
+                       name, line);
+          goto error;
         }
         break;
 
@@ -477,6 +500,11 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
       case(VERSION_CHAR):
         itemsread = sscanf(line, "v %u %u\n", &release_ver, &fileformat_ver);
 
+        if (itemsread == 0) {
+          g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Failed to parse version from buffer.\n");
+          goto error;
+        }
+
         /* 20030921 was the last version which did not have a fileformat */
         /* version.  The below latter test should not happen, but it is here */
         /* just in in case. */
@@ -491,10 +519,9 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
         break;
 
       default:
-        fprintf(stderr, _("Read garbage in [%s] :\n>>\n%s<<\n"),
-                name, line);
+        g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Read garbage in [%s] :\n>>\n%s<<\n"), name, line);
         new_obj = NULL;
-        break;
+        goto error;
     }
 
   }
@@ -510,16 +537,19 @@ GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
 
   if (found_pin) {
     if (release_ver <= VERSION_20020825) {
-      o_pin_update_whichend (toplevel, object_list, found_pin);
+      o_pin_update_whichend (toplevel, new_object_list, found_pin);
     }
   }
 
   tb = s_textbuffer_free(tb);
 
-  object_list = g_list_reverse (object_list);
+  new_object_list = g_list_reverse(new_object_list);
+  object_list = g_list_concat (object_list, new_object_list);
 
   return(object_list);
-
+ error:
+  s_delete_object_glist(toplevel, new_object_list);
+  return NULL;
 }
 
 /*! \brief Read a file
@@ -549,7 +579,7 @@ GList *o_read (TOPLEVEL *toplevel, GList *object_list, char *filename,
   } 
 
   /* Parse file contents */
-  result = o_read_buffer (toplevel, object_list, buffer, size, filename);
+  result = o_read_buffer (toplevel, object_list, buffer, size, filename, err);
   g_free (buffer);
   return result;
 }
diff --git a/libgeda/src/o_arc_basic.c b/libgeda/src/o_arc_basic.c
index 52dadaf..9a20f43 100644
--- a/libgeda/src/o_arc_basic.c
+++ b/libgeda/src/o_arc_basic.c
@@ -230,10 +230,10 @@ void o_arc_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in] buf
  *  \param [in] release_ver
  *  \param [in] fileformat_ver
- *  \return
+ *  \return The ARC OBJECT that was created, or NULL on error.
  */
 OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[],
-		   unsigned int release_ver, unsigned int fileformat_ver)
+           unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
   char type; 
@@ -251,8 +251,11 @@ OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[],
    *  restrictive - the oldest - file format are set to common values
    */
   if(release_ver <= VERSION_20000704) {
-    sscanf(buf, "%c %d %d %d %d %d %d", &type,
-           &x1, &y1, &radius, &start_angle, &end_angle, &color);
+    if (sscanf(buf, "%c %d %d %d %d %d %d", &type,
+	       &x1, &y1, &radius, &start_angle, &end_angle, &color) != 7) {
+      g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to parse arc object\n"));
+      return NULL;
+    }
 
     arc_width = 0;
     arc_end   = END_NONE;
@@ -260,16 +263,19 @@ OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[],
     arc_space = -1;
     arc_length= -1;
   } else {
-    sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d", &type,
-           &x1, &y1, &radius, &start_angle, &end_angle, &color,
-           &arc_width, &arc_end, &arc_type, &arc_length, &arc_space);
-
+    if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d", &type,
+	       &x1, &y1, &radius, &start_angle, &end_angle, &color,
+	       &arc_width, &arc_end, &arc_type, &arc_length, &arc_space) != 12) {
+      g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to parse arc object\n"));
+      return NULL;
+    }
   }
 
   /* Error check */
   if (radius <= 0) {
     s_log_message (_("Found a zero radius arc [ %c %d, %d, %d, %d, %d, %d ]\n"),
                    type, x1, y1, radius, start_angle, end_angle, color);
+    radius = 0;
   }
 	
   if (color < 0 || color > MAX_COLORS) {
diff --git a/libgeda/src/o_attrib.c b/libgeda/src/o_attrib.c
index cd2cb19..93da42c 100644
--- a/libgeda/src/o_attrib.c
+++ b/libgeda/src/o_attrib.c
@@ -226,27 +226,23 @@ void o_attrib_remove(TOPLEVEL *toplevel, GList **list, OBJECT *remove)
  *  Read attributes from a TextBuffer.
  *
  *  \param [in]  toplevel               The TOPLEVEL object.
- *  \param [out] list                   Storage for attributes.
  *  \param [in]  object_to_get_attribs  Object which gets these attribs.
  *  \param [in]  tb                     The text buffer to read from.
  *  \param [in]  release_ver            libgeda release version number.
  *  \param [in]  fileformat_ver         file format version number.
- *  \return GList of attributes read.
+ *  \return GList of attributes read, or NULL on error.
  */
 GList *o_read_attribs (TOPLEVEL *toplevel,
-                       GList *list,
                        OBJECT *object_to_get_attribs,
                        TextBuffer *tb,
-                       unsigned int release_ver, unsigned int fileformat_ver)
+                       unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
 {
-  GList *object_list;
+  GList *object_list = NULL;
   OBJECT *new_obj;
   char *line = NULL;
   char objtype;
   int ATTACH=FALSE;
 
-  object_list = g_list_reverse (list);
-
   while (1) {
 
     line = s_textbuffer_next_line (tb);
@@ -256,66 +252,78 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
     switch (objtype) {
 
       case(OBJ_LINE):
-        new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
 
       case(OBJ_NET):
-        new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_BUS):
-        new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_BOX):
-        new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_CIRCLE):
-        new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_COMPLEX):
       case(OBJ_PLACEHOLDER):
-        new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_PATH):
         line = g_strdup (line);
-        new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver);
+        new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err);
         g_free (line);
+        if (new_obj == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_PIN):
-        new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_ARC):
-        new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver);
+        if ((new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         break;
 
       case(OBJ_TEXT):
         line = g_strdup (line);
-        new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver);
+        new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err);
         g_free (line);
+        if (new_obj == NULL)
+          goto error;
         object_list = g_list_prepend (object_list, new_obj);
         ATTACH=TRUE;
 
         break;
 
-      case(ENDATTACH_ATTR): 
+      case(ENDATTACH_ATTR):
         object_list = g_list_reverse (object_list);
-        return(object_list);
+        return object_list;
         break;
 
     }
@@ -324,11 +332,17 @@ GList *o_read_attribs (TOPLEVEL *toplevel,
       o_attrib_attach (toplevel, new_obj, object_to_get_attribs, FALSE);
       ATTACH=FALSE;
     } else {
-      fprintf(stderr, "Tried to attach a non-text item as an attribute\n");
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Tried to attach a non-text item as an attribute\n"));
+      goto error;
     }
   }
   object_list = g_list_reverse (object_list);
+
   return(object_list);
+
+error:
+  s_delete_object_glist(toplevel, object_list);
+  return NULL;
 }
 
 
diff --git a/libgeda/src/o_box_basic.c b/libgeda/src/o_box_basic.c
index 144d89c..66b97fe 100644
--- a/libgeda/src/o_box_basic.c
+++ b/libgeda/src/o_box_basic.c
@@ -256,10 +256,10 @@ void o_box_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in]     buf             Character string with box description.
  *  \param [in]     release_ver     libgeda release version number.
  *  \param [in]     fileformat_ver  libgeda file format version number.
- *  \return The BOX OBJECT that was created.
+ *  \return The BOX OBJECT that was created, or NULL on error.
  */
 OBJECT *o_box_read (TOPLEVEL *toplevel, char buf[],
-                    unsigned int release_ver, unsigned int fileformat_ver)
+                    unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
   char type;
@@ -282,8 +282,11 @@ OBJECT *o_box_read (TOPLEVEL *toplevel, char buf[],
    *  to default.
    */
 
-    sscanf (buf, "%c %d %d %d %d %d\n",
-            &type, &x1, &y1, &width, &height, &color);
+    if (sscanf (buf, "%c %d %d %d %d %d\n",
+		&type, &x1, &y1, &width, &height, &color) != 6) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse box object\n"));
+      return NULL;
+    }
 
     box_width   = 0;
     box_end     = END_NONE;
@@ -305,11 +308,14 @@ OBJECT *o_box_read (TOPLEVEL *toplevel, char buf[],
      *  characters and numbers in plain ASCII on a single line. The meaning of
      *  each item is described in the file format documentation.
      */
-    sscanf (buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
-            &type, &x1, &y1, &width, &height, &color,
-            &box_width, &box_end, &box_type, &box_length,
-            &box_space, &box_filling,
-            &fill_width, &angle1, &pitch1, &angle2, &pitch2);
+    if (sscanf (buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+		&type, &x1, &y1, &width, &height, &color,
+		&box_width, &box_end, &box_type, &box_length,
+		&box_space, &box_filling,
+		&fill_width, &angle1, &pitch1, &angle2, &pitch2) != 17) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse box object\n"));
+      return NULL;
+    }
   }
 
   if (width == 0 || height == 0) {
diff --git a/libgeda/src/o_bus_basic.c b/libgeda/src/o_bus_basic.c
index ac1841e..c87c01c 100644
--- a/libgeda/src/o_bus_basic.c
+++ b/libgeda/src/o_bus_basic.c
@@ -143,10 +143,10 @@ void o_bus_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in] buf          a text buffer (usually a line of a schematic file)
  *  \param [in] release_ver  The release number gEDA
  *  \param [in] fileformat_ver a integer value of the file format
- *  \return The object list
+ *  \return The object list, or NULL on error.
  */
 OBJECT *o_bus_read (TOPLEVEL *toplevel, char buf[],
-                    unsigned int release_ver, unsigned int fileformat_ver)
+                    unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
   char type; 
@@ -156,11 +156,17 @@ OBJECT *o_bus_read (TOPLEVEL *toplevel, char buf[],
   int ripper_dir;
 
   if (release_ver <= VERSION_20020825) {
-    sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
+    if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse bus object\n"));
+      return NULL;
+    }
     ripper_dir = 0;
   } else {
-    sscanf (buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color,
-            &ripper_dir);
+    if (sscanf (buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color,
+		&ripper_dir) != 7) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse bus object\n"));
+      return NULL;
+    }
   }
 
   if (x1 == x2 && y1 == y2) {
diff --git a/libgeda/src/o_circle_basic.c b/libgeda/src/o_circle_basic.c
index 92c839a..da43b73 100644
--- a/libgeda/src/o_circle_basic.c
+++ b/libgeda/src/o_circle_basic.c
@@ -220,10 +220,10 @@ void o_circle_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in]  buf             Character string with circle description.
  *  \param [in]  release_ver     libgeda release version number.
  *  \param [in]  fileformat_ver  libgeda file format version number.
- *  \return A pointer to the new circle object.
+ *  \return A pointer to the new circle object, or NULL on error.
  */
 OBJECT *o_circle_read (TOPLEVEL *toplevel, char buf[],
-		      unsigned int release_ver, unsigned int fileformat_ver)
+              unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
 {
   OBJECT *new_obj;
   char type; 
@@ -242,7 +242,10 @@ OBJECT *o_circle_read (TOPLEVEL *toplevel, char buf[],
      * handle the line type and the filling of the box object. They are set
      * to default.
      */
-    sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color);
+    if (sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color) != 5) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse circle object\n"));
+      return NULL;
+    }
 
     circle_width = 0;
     circle_end   = END_NONE;
@@ -264,18 +267,22 @@ OBJECT *o_circle_read (TOPLEVEL *toplevel, char buf[],
      * list of characters and numbers in plain ASCII on a single line. The
      * meaning of each item is described in the file format documentation.
      */  
-    sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
-	   &type, &x1, &y1, &radius, &color,
-	   &circle_width, &circle_end, &circle_type,
-	   &circle_length, &circle_space, &circle_fill,
-	   &fill_width, &angle1, &pitch1, &angle2, &pitch2);
+    if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+	       &type, &x1, &y1, &radius, &color,
+	       &circle_width, &circle_end, &circle_type,
+	       &circle_length, &circle_space, &circle_fill,
+	       &fill_width, &angle1, &pitch1, &angle2, &pitch2) != 16) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse circle object\n"));
+      return NULL;
+    }
   }
 
 
-  if (radius == 0) {
-    s_log_message(_("Found a zero radius circle [ %c %d %d %d %d ]\n"),
+  if (radius <= 0) {
+    s_log_message(_("Found a zero or negative radius circle [ %c %d %d %d %d ]\n"),
                   type, x1, y1, radius, color);
-	
+    s_log_message (_("Setting radius to 0\n"));
+    radius = 0;
   }
   
   if (color < 0 || color > MAX_COLORS) {
diff --git a/libgeda/src/o_complex_basic.c b/libgeda/src/o_complex_basic.c
index 6ae71b2..88ad6d0 100644
--- a/libgeda/src/o_complex_basic.c
+++ b/libgeda/src/o_complex_basic.c
@@ -395,62 +395,13 @@ static void o_complex_remove_promotable_attribs (TOPLEVEL *toplevel, OBJECT *obj
   g_list_free (promotable);
 }
 
-
-/* Done */
-/*! \brief
- *  \par Function Description
- *
- */
-OBJECT *o_complex_new(TOPLEVEL *toplevel,
-		      char type,
-		      int color, int x, int y, int angle,
-		      int mirror, const CLibSymbol *clib,
-		      const gchar *basename,
-		      int selectable)
+static void create_placeholder(TOPLEVEL * toplevel, OBJECT * new_node, int x, int y)
 {
-  OBJECT *new_node=NULL;
-  OBJECT *new_prim_obj;
-  GList *prim_objs;
-  GList *iter;
-  int loaded_normally = FALSE;
-
-  gchar *buffer = NULL;
-
-  new_node = s_basic_new_object(type, "complex");
-
-  if (clib != NULL) {
-    new_node->complex_basename = g_strdup (s_clib_symbol_get_name (clib));
-  } else {
-    new_node->complex_basename = g_strdup (basename);
-  }
-
-
-  new_node->complex_embedded = FALSE;
-  new_node->color = color;
-  new_node->selectable = selectable;
-
-  new_node->complex = (COMPLEX *) g_malloc(sizeof(COMPLEX));
-  new_node->complex->angle = angle;
-  new_node->complex->mirror = mirror;
-  new_node->complex->x = x;
-  new_node->complex->y = y;
-
-  prim_objs = NULL;
-
-  /* get the symbol data */
-  if (clib != NULL) {
-    buffer = s_clib_symbol_get_data (clib);
-  }
-
-  if (clib == NULL || buffer == NULL) {
-
+    OBJECT *new_prim_obj;
     char *not_found_text = NULL;
     int left, right, top, bottom;
     int x_offset, y_offset;
 
-    /* filename was NOT found */
-    loaded_normally = FALSE;
-
     /* Put placeholder into object list.  Changed by SDB on
      * 1.19.2005 to fix problem that symbols were silently
      * deleted by gattrib when RC files were messed up.  */
@@ -460,23 +411,23 @@ OBJECT *o_complex_new(TOPLEVEL *toplevel,
     new_prim_obj = o_line_new(toplevel, OBJ_LINE,
                            DETACHED_ATTRIBUTE_COLOR,
                            x - 50, y, x + 50, y);
-    prim_objs = g_list_append (prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj);
     new_prim_obj = o_line_new(toplevel, OBJ_LINE,
                            DETACHED_ATTRIBUTE_COLOR,
                            x, y + 50, x, y - 50); 
-    prim_objs = g_list_append (prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj);
 
     /* Add some useful text */
     not_found_text = 
       g_strdup_printf (_("Component not found:\n %s"),
-		       new_node->complex_basename);
+           new_node->complex_basename);
     new_prim_obj = o_text_new(toplevel,
                            OBJ_TEXT, DETACHED_ATTRIBUTE_COLOR, 
                            x + NOT_FOUND_TEXT_X, 
                            y + NOT_FOUND_TEXT_Y, LOWER_LEFT, 0, 
                            not_found_text, 8,
                            VISIBLE, SHOW_NAME_VALUE);
-    prim_objs = g_list_append (prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj);
     g_free(not_found_text);
 
     /* figure out where to put the hazard triangle */
@@ -493,7 +444,7 @@ OBJECT *o_complex_new(TOPLEVEL *toplevel,
                            y + NOT_FOUND_TEXT_Y + y_offset); 
     o_set_line_options(toplevel, new_prim_obj, END_ROUND, TYPE_SOLID,
                        50, -1, -1);
-    prim_objs = g_list_append (prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj);
     new_prim_obj = o_line_new(toplevel, OBJ_LINE,
                            DETACHED_ATTRIBUTE_COLOR,
                            x + NOT_FOUND_TEXT_X + x_offset, 
@@ -502,7 +453,7 @@ OBJECT *o_complex_new(TOPLEVEL *toplevel,
                            y + NOT_FOUND_TEXT_Y + y_offset + 500); 
     o_set_line_options(toplevel, new_prim_obj, END_ROUND, TYPE_SOLID,
                        50, -1, -1);
-    prim_objs = g_list_append (prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj);
     new_prim_obj = o_line_new(toplevel, OBJ_LINE,
                            DETACHED_ATTRIBUTE_COLOR,
                            x + NOT_FOUND_TEXT_X + x_offset + 300, 
@@ -511,43 +462,85 @@ OBJECT *o_complex_new(TOPLEVEL *toplevel,
                            y + NOT_FOUND_TEXT_Y + y_offset); 
     o_set_line_options(toplevel, new_prim_obj, END_ROUND, TYPE_SOLID,
                        50, -1, -1);
-    prim_objs = g_list_append (prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj);
     new_prim_obj = o_text_new(toplevel,
                            OBJ_TEXT, DETACHED_ATTRIBUTE_COLOR, 
                            x + NOT_FOUND_TEXT_X + x_offset + 270, 
                            y + NOT_FOUND_TEXT_Y + y_offset + 90, 
                            LOWER_LEFT, 0, "!", 18,
                            VISIBLE, SHOW_NAME_VALUE);
-    prim_objs = g_list_append (prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj);
+    new_node->complex->prim_objs = g_list_reverse(new_node->complex->prim_objs);
+}
+
+/* Done */
+/*! \brief
+ *  \par Function Description
+ *
+ */
+OBJECT *o_complex_new(TOPLEVEL *toplevel,
+		      char type,
+		      int color, int x, int y, int angle,
+		      int mirror, const CLibSymbol *clib,
+		      const gchar *basename,
+		      int selectable)
+{
+  OBJECT *new_node=NULL;
+  GList *iter;
+  gchar *buffer = NULL;
 
+  new_node = s_basic_new_object(type, "complex");
+
+  if (clib != NULL) {
+    new_node->complex_basename = g_strdup (s_clib_symbol_get_name (clib));
   } else {
+    new_node->complex_basename = g_strdup (basename);
+  }
 
-    /* filename was found */
-    loaded_normally = TRUE;
 
-    /* add connections till translated */
-    prim_objs = o_read_buffer (toplevel, prim_objs, buffer, -1, new_node->complex_basename);
+  new_node->complex_embedded = FALSE;
+  new_node->color = color;
+  new_node->selectable = selectable;
 
-    g_free (buffer);
+  new_node->complex = (COMPLEX *) g_malloc(sizeof(COMPLEX));
+  new_node->complex->prim_objs = NULL;
+  new_node->complex->angle = angle;
+  new_node->complex->mirror = mirror;
+  new_node->complex->x = x;
+  new_node->complex->y = y;
 
+  /* get the symbol data */
+  if (clib != NULL) {
+    buffer = s_clib_symbol_get_data (clib);
   }
 
-  /* do not mirror/rotate/translate/connect the primitive objects if the
-   * component was not loaded via o_read 
-   */
-  if (loaded_normally == TRUE) {
-    if (mirror) {
-      o_glist_mirror_world (toplevel, 0, 0, prim_objs);
+  if (clib == NULL || buffer == NULL)
+    create_placeholder(toplevel, new_node, x, y);
+  else {
+    GError * err = NULL;
+
+    /* add connections till translated */
+    new_node->complex->prim_objs = o_read_buffer (toplevel, NULL, buffer, -1, new_node->complex_basename, &err);
+    if (err) {
+      g_error_free(err);
+      /* If reading fails, replace with placeholder object */
+      create_placeholder(toplevel, new_node, x, y);
+    }
+    else {
+      if (mirror) {
+        o_glist_mirror_world (toplevel, 0, 0, new_node->complex->prim_objs);
+      }
+      
+      o_glist_rotate_world (toplevel, 0, 0, angle, new_node->complex->prim_objs);
+      o_glist_translate_world (toplevel, x, y, new_node->complex->prim_objs);
     }
 
-    o_glist_rotate_world (toplevel, 0, 0, angle, prim_objs);
-    o_glist_translate_world (toplevel, x, y, prim_objs);
-  }
+    g_free (buffer);
 
-  new_node->complex->prim_objs = prim_objs;
+  }
 
   /* set the parent field now */
-  for (iter = prim_objs; iter != NULL; iter = g_list_next (iter)) {
+  for (iter = new_node->complex->prim_objs; iter != NULL; iter = g_list_next (iter)) {
     OBJECT *tmp = iter->data;
     tmp->parent = new_node;
   }
@@ -640,11 +633,11 @@ void o_complex_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in] buf          a text buffer (usually a line of a schematic file)
  *  \param [in] release_ver  The release number gEDA
  *  \param [in] fileformat_ver a integer value of the file format
- *  \return The object list
+ *  \return The object list, or NULL on error.
  */
 OBJECT *o_complex_read (TOPLEVEL *toplevel,
                         char buf[], unsigned int release_ver,
-                        unsigned int fileformat_ver)
+                        unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
   char type; 
@@ -656,8 +649,11 @@ OBJECT *o_complex_read (TOPLEVEL *toplevel,
   int selectable;
   int mirror;
 
-  sscanf(buf, "%c %d %d %d %d %d %s\n",
-         &type, &x1, &y1, &selectable, &angle, &mirror, basename);
+  if (sscanf(buf, "%c %d %d %d %d %d %s\n",
+	     &type, &x1, &y1, &selectable, &angle, &mirror, basename) != 7) {
+    g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse complex object\n"));
+    return NULL;
+  }
 
   switch(angle) {
 
@@ -669,7 +665,8 @@ OBJECT *o_complex_read (TOPLEVEL *toplevel,
 
     default:
       s_log_message(_("Found a component with an invalid rotation [ %c %d %d %d %d %d %s ]\n"), type, x1, y1, selectable, angle, mirror, basename);
-      break;
+      s_log_message (_("Setting angle to 0\n"));
+      angle = 0;
   }
 
   switch(mirror) {
@@ -681,7 +678,8 @@ OBJECT *o_complex_read (TOPLEVEL *toplevel,
 		
     default:
       s_log_message(_("Found a component with an invalid mirror flag [ %c %d %d %d %d %d %s ]\n"), type, x1, y1, selectable, angle, mirror, basename);
-      break;
+      s_log_message (_("Setting mirror to 0\n"));
+      mirror = 0;
   }
   if (strncmp(basename, "EMBEDDED", 8) == 0) {
     
@@ -699,7 +697,8 @@ OBJECT *o_complex_read (TOPLEVEL *toplevel,
                                 angle, mirror, clib,
                                 basename, selectable);
     /* Delete or hide attributes eligible for promotion inside the complex */
-     o_complex_remove_promotable_attribs (toplevel, new_obj);
+    if (new_obj)
+      o_complex_remove_promotable_attribs (toplevel, new_obj);
   }
 
   g_free (basename);
diff --git a/libgeda/src/o_line_basic.c b/libgeda/src/o_line_basic.c
index 887c525..19fb3b7 100644
--- a/libgeda/src/o_line_basic.c
+++ b/libgeda/src/o_line_basic.c
@@ -204,10 +204,10 @@ void o_line_modify(TOPLEVEL *toplevel, OBJECT *object,
  *  \param [in]  buf             Character string with line description.
  *  \param [in]  release_ver     libgeda release version number.
  *  \param [in]  fileformat_ver  libgeda file format version number.
- *  \return A pointer to the new line object.
+ *  \return A pointer to the new line object, or NULL on error.
  */
 OBJECT *o_line_read (TOPLEVEL *toplevel, char buf[],
-                     unsigned int release_ver, unsigned int fileformat_ver)
+                     unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
 {
   OBJECT *new_obj;
   char type;
@@ -224,8 +224,11 @@ OBJECT *o_line_read (TOPLEVEL *toplevel, char buf[],
      * not handle the line type and the filling - here filling is irrelevant.
      * They are set to default.
      */
-    sscanf (buf, "%c %d %d %d %d %d\n", &type,
-            &x1, &y1, &x2, &y2, &color);
+    if (sscanf (buf, "%c %d %d %d %d %d\n", &type,
+		&x1, &y1, &x2, &y2, &color) != 6) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse line object\n"));
+      return NULL;
+    }
 
     line_width = 0;
     line_end   = END_NONE;
@@ -238,9 +241,12 @@ OBJECT *o_line_read (TOPLEVEL *toplevel, char buf[],
      * list of characters and numbers in plain ASCII on a single line.
      * The meaning of each item is described in the file format documentation.
      */
-    sscanf (buf, "%c %d %d %d %d %d %d %d %d %d %d\n", &type,
-            &x1, &y1, &x2, &y2, &color,
-            &line_width, &line_end, &line_type, &line_length, &line_space);
+      if (sscanf (buf, "%c %d %d %d %d %d %d %d %d %d %d\n", &type,
+		  &x1, &y1, &x2, &y2, &color,
+		  &line_width, &line_end, &line_type, &line_length, &line_space) != 11) {
+        g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse line object\n"));
+        return NULL;
+      }
   }
 
   /*
diff --git a/libgeda/src/o_net_basic.c b/libgeda/src/o_net_basic.c
index 3fa642f..3ae39fa 100644
--- a/libgeda/src/o_net_basic.c
+++ b/libgeda/src/o_net_basic.c
@@ -140,11 +140,11 @@ void o_net_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in] buf          a text buffer (usually a line of a schematic file)
  *  \param [in] release_ver  The release number gEDA
  *  \param [in] fileformat_ver a integer value of the file format
- *  \return The object list
+ *  \return The object list, or NULL on error.
  *
  */
 OBJECT *o_net_read (TOPLEVEL *toplevel, char buf[],
-                    unsigned int release_ver, unsigned int fileformat_ver)
+                    unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
   char type;
@@ -152,7 +152,10 @@ OBJECT *o_net_read (TOPLEVEL *toplevel, char buf[],
   int x2, y2;
   int color;
 
-  sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
+  if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
+        g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse net object\n"));
+    return NULL;
+  }
 
   if (x1 == x2 && y1 == y2) {
     s_log_message (_("Found a zero length net [ %c %d %d %d %d %d ]\n"),
diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index b71e30a..8a7f2d1 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -150,11 +150,11 @@ OBJECT *o_path_copy (TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in]  tb              Text buffer containing the path string.
  *  \param [in]  release_ver     libgeda release version number.
  *  \param [in]  fileformat_ver  libgeda file format version number.
- *  \return A pointer to the new path object.
+ *  \return A pointer to the new path object, or NULL on error;
  */
 OBJECT *o_path_read (TOPLEVEL *toplevel,
                      const char *first_line, TextBuffer *tb,
-                     unsigned int release_ver, unsigned int fileformat_ver)
+                     unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
   char type;
@@ -174,10 +174,13 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
    * The meaning of each item is described in the file format documentation.
    */
   /* Allocate enough space */
-  sscanf (first_line, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
-          &type, &color, &line_width, &line_end, &line_type,
-          &line_length, &line_space, &fill_type, &fill_width, &angle1,
-          &pitch1, &angle2, &pitch2, &num_lines);
+  if (sscanf (first_line, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+	      &type, &color, &line_width, &line_end, &line_type,
+	      &line_length, &line_space, &fill_type, &fill_width, &angle1,
+	      &pitch1, &angle2, &pitch2, &num_lines) != 14) {
+    g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse path object\n"));
+    return NULL;
+  }
 
   /*
    * Checks if the required color is valid.
@@ -200,9 +203,13 @@ OBJECT *o_path_read (TOPLEVEL *toplevel,
 
     line = s_textbuffer_next_line (tb);
 
-    if (line != NULL) {
-      pathstr = g_string_append (pathstr, line);
+    if (line == NULL) {
+      g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Premature eof when reading path\n"));
+      g_free (string);
+      return NULL;
     }
+
+    pathstr = g_string_append (pathstr, line);
   }
 
   /* retrieve the character string from the GString */
diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index 43b1124..e8e4d01 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -45,13 +45,14 @@
  *  \param [in]  tb              Text buffer to load embedded data from.
  *  \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.
+ *  \return A pointer to the new picture object, or NULL on error.
  */
 OBJECT *o_picture_read (TOPLEVEL *toplevel,
 		       const char *first_line,
 		       TextBuffer *tb,
 		       unsigned int release_ver,
-		       unsigned int fileformat_ver)
+               unsigned int fileformat_ver,
+               GError **err)
 {
   OBJECT *new_obj;
   int x1, y1;
@@ -68,8 +69,9 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
 	 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
   
   if (num_conv != 8) {
-    s_log_message (_("Error reading picture definition line: %s.\n"),
-                   first_line);
+    g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Error reading picture definition line: %s.\n"),
+                                              first_line);
+    return NULL;
   }
 
   if (width == 0 || height == 0) {
@@ -149,6 +151,46 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
     }
   }
 
+  /* If we have embedded data, try loading from the decoded buffer */
+  if (file_content != NULL) {
+    pixbuf = o_picture_pixbuf_from_buffer (file_content, file_length, err);
+    if (err != NULL) {
+      s_log_message (_("Failed to load image from embedded data [%s]: %s\n"),
+                     filename, *err->message);
+      s_log_message (_("Falling back to file loading. Picture unembedded.\n"));
+      g_error_free (err);
+      *err = NULL;
+      embedded = 0;
+    }
+  }
+
+  /* If we haven't loaded the pixbuf above, try loading from file */
+  if (pixbuf == NULL) {
+    pixbuf = gdk_pixbuf_new_from_file (filename, err);
+    if (*err != NULL) {
+      s_log_message (_("Failed to load image from file [%s]: %s\n"),
+                     filename, *err->message);
+      g_error_free (*err);
+      *err = NULL;
+    }
+  }
+
+  /* If the pixbuf couldn't be loaded, then try to load a warning picture */
+  if (pixbuf == NULL) {
+    char *temp_filename;
+
+    s_log_message (_("Loading warning picture.\n"));
+    
+    temp_filename = g_build_filename (toplevel->bitmap_directory,
+                                      "gschem-warning.png", NULL);
+    pixbuf = gdk_pixbuf_new_from_file (temp_filename, NULL);
+    if (pixbuf == NULL) {
+      s_log_message( _("Error loading picture from file: %s.\n"),
+                     temp_filename);
+    }      
+    g_free (temp_filename);
+  }
+  
   /* create the picture */
   /* The picture is described by its upper left and lower right corner */
   new_obj = o_picture_new (toplevel, file_content, file_length, filename,
diff --git a/libgeda/src/o_pin_basic.c b/libgeda/src/o_pin_basic.c
index ef91efb..8186b08 100644
--- a/libgeda/src/o_pin_basic.c
+++ b/libgeda/src/o_pin_basic.c
@@ -142,10 +142,10 @@ void o_pin_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in] buf          a text buffer (usually a line of a schematic file)
  *  \param [in] release_ver  The release number gEDA
  *  \param [in] fileformat_ver a integer value of the file format
- *  \return The object list
+ *  \return The object list, or NULL on error.
  */
 OBJECT *o_pin_read (TOPLEVEL *toplevel, char buf[],
-                    unsigned int release_ver, unsigned int fileformat_ver)
+                    unsigned int release_ver, unsigned int fileformat_ver, GError **err)
 {
   OBJECT *new_obj;
   char type; 
@@ -156,12 +156,18 @@ OBJECT *o_pin_read (TOPLEVEL *toplevel, char buf[],
   int whichend;
 
   if (release_ver <= VERSION_20020825) {
-    sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
+    if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse pin object\n"));
+      return NULL;
+    }
     pin_type = PIN_TYPE_NET;
     whichend = -1;
   } else {
-    sscanf (buf, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2,
-            &color, &pin_type, &whichend);
+    if (sscanf (buf, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2,
+		&color, &pin_type, &whichend) != 8) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse pin object\n"));
+      return NULL;
+    }
   }
 
   if (whichend == -1) {
diff --git a/libgeda/src/o_text_basic.c b/libgeda/src/o_text_basic.c
index 2b7afe0..664c9c2 100644
--- a/libgeda/src/o_text_basic.c
+++ b/libgeda/src/o_text_basic.c
@@ -325,13 +325,14 @@ void o_text_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
  *  \param [in] tb           a text buffer (usually a line of a schematic file)
  *  \param [in] release_ver  The release number gEDA
  *  \param [in] fileformat_ver a integer value of the file format
- *  \return The object list
+ *  \return The object list, or NULL on error.
  */
 OBJECT *o_text_read (TOPLEVEL *toplevel,
 		    const char *first_line,
 		    TextBuffer *tb,
 		    unsigned int release_ver,
-		    unsigned int fileformat_ver)
+            unsigned int fileformat_ver,
+            GError **err)
 {
   OBJECT *new_obj;
   char type; 
@@ -348,24 +349,33 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
   GString *textstr;
 
   if (fileformat_ver >= 1) {
-    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);	
+    if (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) != 10) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse text object\n"));
+      return NULL;
+    }
   } else if (release_ver < VERSION_20000220) {
     /* yes, above less than (not less than and equal) is correct. The format */
     /* change occurred in 20000220 */
-    sscanf(first_line, "%c %d %d %d %d %d %d %d\n", &type, &x, &y, 
-           &color, &size,
-           &visibility, &show_name_value, 
-           &angle);	
+    if (sscanf(first_line, "%c %d %d %d %d %d %d %d\n", &type, &x, &y, 
+	       &color, &size,
+	       &visibility, &show_name_value, 
+	       &angle) != 8) {
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse text object\n"));
+      return NULL;
+    }
     alignment = LOWER_LEFT; /* older versions didn't have this */
     num_lines = 1; /* only support a single line */
   } else {
-    sscanf(first_line, "%c %d %d %d %d %d %d %d %d\n", &type, &x, &y, 
-           &color, &size,
-           &visibility, &show_name_value, 
-           &angle, &alignment);	
+    if (sscanf(first_line, "%c %d %d %d %d %d %d %d %d\n", &type, &x, &y, 
+	       &color, &size,
+	       &visibility, &show_name_value, 
+           &angle, &alignment) != 9) {
+      g_set_error (err, EDA_ERROR, EDA_ERROR_READ, _("Failed to parse text object\n"));
+      return NULL;
+    }
     num_lines = 1; /* only support a single line */
   }
 
@@ -425,10 +435,13 @@ OBJECT *o_text_read (TOPLEVEL *toplevel,
     
     line = s_textbuffer_next_line (tb);
 
-    if (line != NULL)
-      {
-	textstr = g_string_append (textstr, line);
-      }
+    if (line == NULL) {
+      g_string_free (textstr, TRUE);
+      g_set_error(err, EDA_ERROR, EDA_ERROR_READ, _("Premature end of data after %d lines\n"), i);
+      return 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/scheme_init.c b/libgeda/src/scheme_init.c
index a9da63e..9fa7d51 100644
--- a/libgeda/src/scheme_init.c
+++ b/libgeda/src/scheme_init.c
@@ -30,6 +30,7 @@
 static int init_called = 0;
 
 SCM_GLOBAL_SYMBOL (edascm_object_state_sym, "object-state");
+SCM_GLOBAL_SYMBOL (edascm_invalid_string_sym , "invalid-string");
 
 /*! \brief Initialise the Scheme API.
  * \par Function Description
diff --git a/libgeda/src/scheme_page.c b/libgeda/src/scheme_page.c
index 311abb5..e2f1c2d 100644
--- a/libgeda/src/scheme_page.c
+++ b/libgeda/src/scheme_page.c
@@ -400,14 +400,12 @@ SCM_DEFINE (page_to_string, "%page->string", 1, 0, 0,
 /*! \brief Create a page from a string representation.
  * \par Function Description
  * Returns a page with filename \a filename_s created by parsing \a
- * str_s.
+ * str_s. Throws an error if \a str_s contains invalid gEDA file
+ * format syntax.
  *
  * \note Scheme API: Implements the %string->page procedure of the
  * (geda core page) module.
  *
- * \bug Should throw an error if \a str_s contains invalid gEDA file
- * format syntax.  Requires support in gEDA file parser.
- *
  * \param filename_s Filename for new page.
  * \param str_s      String to parse to create page.
  * \return a new page created by parsing \a str_s.
@@ -428,11 +426,20 @@ SCM_DEFINE (string_to_page, "%string->page", 2, 0, 0,
   free (filename);
 
   size_t len;
+  GError * err = NULL;
   char *str = scm_to_utf8_stringn (str_s, &len);
   GList *objects = o_read_buffer (toplevel, NULL, str, len,
-                                  page->page_filename);
+                                  page->page_filename, &err);
   free (str);
 
+  if (err) {
+      SCM error_message = scm_from_utf8_string (err->message);
+
+      g_error_free(err);
+      scm_error (edascm_invalid_string_sym, s_string_to_page,
+                 _("Invalid string: ~s"), scm_list_1 (error_message), SCM_EOL);
+  }
+
   s_page_append_list (toplevel, page, objects);
 
   return edascm_from_page (page);




_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs