SF.net SVN: geany-plugins:[169] trunk

yurand at users.sourceforge.net yurand at xxxxx
Sun Sep 7 20:36:11 UTC 2008


Revision: 169
          http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=169&view=rev
Author:   yurand
Date:     2008-09-07 20:36:07 +0000 (Sun, 07 Sep 2008)

Log Message:
-----------
Added geanydebug plugin

Added Paths:
-----------
    trunk/geanydebug/
    trunk/geanydebug/.gitignore
    trunk/geanydebug/AUTHORS
    trunk/geanydebug/COPYING
    trunk/geanydebug/ChangeLog
    trunk/geanydebug/INSTALL
    trunk/geanydebug/Makefile.am
    trunk/geanydebug/NEWS
    trunk/geanydebug/README
    trunk/geanydebug/THANKS
    trunk/geanydebug/autogen.sh
    trunk/geanydebug/configure.in
    trunk/geanydebug/indent-all.sh
    trunk/geanydebug/makefile.win32
    trunk/geanydebug/po/
    trunk/geanydebug/po/.gitignore
    trunk/geanydebug/po/ChangeLog
    trunk/geanydebug/po/LINGUAS
    trunk/geanydebug/po/POTFILES.in
    trunk/geanydebug/po/POTFILES.skip
    trunk/geanydebug/src/
    trunk/geanydebug/src/Makefile.am
    trunk/geanydebug/src/gdb-io-break.c
    trunk/geanydebug/src/gdb-io-envir.c
    trunk/geanydebug/src/gdb-io-frame.c
    trunk/geanydebug/src/gdb-io-priv.h
    trunk/geanydebug/src/gdb-io-read.c
    trunk/geanydebug/src/gdb-io-run.c
    trunk/geanydebug/src/gdb-io-stack.c
    trunk/geanydebug/src/gdb-io.h
    trunk/geanydebug/src/gdb-lex.c
    trunk/geanydebug/src/gdb-lex.h
    trunk/geanydebug/src/gdb-ui-break.c
    trunk/geanydebug/src/gdb-ui-envir.c
    trunk/geanydebug/src/gdb-ui-frame.c
    trunk/geanydebug/src/gdb-ui-locn.c
    trunk/geanydebug/src/gdb-ui-main.c
    trunk/geanydebug/src/gdb-ui.h
    trunk/geanydebug/src/geanydebug.c
    trunk/geanydebug/src/ttyhelper.c
    trunk/geanydebug/tests/
    trunk/geanydebug/tests/Makefile.am
    trunk/geanydebug/tests/unittests.c

Added: trunk/geanydebug/.gitignore
===================================================================
--- trunk/geanydebug/.gitignore	                        (rev 0)
+++ trunk/geanydebug/.gitignore	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,26 @@
+autom4te.cache
+Makefile
+Makefile.in
+aclocal.m4
+config.log
+config.status
+config.guess
+config.sub
+config.h
+config.h.in
+configure
+.deps
+.libs
+*.o
+*.la
+*.lo
+libtool
+*.tar.gz
+unittests
+ltmain.sh
+depcomp
+install-sh
+missing
+intltool-*
+mkinstalldirs
+stamp-h1

Added: trunk/geanydebug/AUTHORS
===================================================================
--- trunk/geanydebug/AUTHORS	                        (rev 0)
+++ trunk/geanydebug/AUTHORS	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1 @@
+Jeff Pohlmeyer <yetanothergeek at gmail.com>

Added: trunk/geanydebug/COPYING
===================================================================
--- trunk/geanydebug/COPYING	                        (rev 0)
+++ trunk/geanydebug/COPYING	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: trunk/geanydebug/Makefile.am
===================================================================
--- trunk/geanydebug/Makefile.am	                        (rev 0)
+++ trunk/geanydebug/Makefile.am	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,22 @@
+SUBDIRS = src po tests
+
+EXTRA_DIST =				\
+	autogen.sh				\
+	makefile.win32			\
+	intltool-extract.in		\
+	intltool-merge.in		\
+	intltool-update.in		\
+	indent-all.sh
+
+DISTCLEANFILES =			\
+	intltool-extract		\
+	intltool-merge			\
+	intltool-update
+
+.PHONY: ChangeLog mrproper
+
+ChangeLog:
+	git log > ChangeLog
+
+mrproper:
+	git clean -d -x -f

Added: trunk/geanydebug/NEWS
===================================================================
--- trunk/geanydebug/NEWS	                        (rev 0)
+++ trunk/geanydebug/NEWS	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1 @@
+See "ChangeLog"

Added: trunk/geanydebug/README
===================================================================
--- trunk/geanydebug/README	                        (rev 0)
+++ trunk/geanydebug/README	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,48 @@
+
+This is a plugin to provide integrated debugging from Geany using the GNU
+debugger (gdb). It was developed and tested on openSUSE-10.3 with GDB-6.7.50.
+Other recent versions of GDB will probably work, but operating systems other
+than Linux-PC will not work, at least not without some considerable hacking.
+
+There is no real documentation, but if you hover your mouse over the buttons
+in the "Debug" sidebar panel in Geany the tooltips should give you some idea
+of what to do next. There are also a few "rough draft" notes below:
+
+Most of the console output from GDB is sent to the "Compiler" message window
+in Geany, and you can send standard commands to GDB using the "Console" entry
+on the debug sidebar. This should be used with caution, since GDB's machine
+interface and console interface don't always play well together.
+
+Also note that the plugin sets its own internal breakpoint #1 to grab the
+program's PID on startup, so any user-specified breakpoint numbers begin
+at #2, and if you manually delete the #1 breakpoint it will likely cause
+you some problems.
+
+Whenever the target program hits a breakpoint or encounters a segfault etc.
+it will try to open the appropriate source file and jump to the correct line.
+
+To examine the state of the program's variables, you can click on the "Stack"
+button in the debug sidebar. Note that the interaction between the plugin and
+the debugger can sometimes be quite slow, so please be patient when waiting
+for the dialogs to open.
+
+The "Add breakpoint", "Add watchpoint", and "Run to" dialogs will try to
+suggest some values based on your current position in whatever file you
+have open in Geany, but if you don't like the choice, just click the "Clear"
+button and type in whatever you please.
+
+The plugin tries to enable only the buttons that are relevant to the current
+state, but ocassionally it might end up getting things wrong. If this happens,
+you should be able to click the "Unload" button and everything will be reset.
+
+If you try to unload the plugin using the plugin manager while it has a
+program loaded, the plugin manager might appear to hang for a few seconds,
+while GDB tries to shut down. Again, just be patient, but note that it is
+much better use the "Unload" button in the debug sidebar before trying to
+disable the plugin.
+
+There also seems to be some conflict with the GeanyLua plugin, if you have
+any ~/.geany/plugins/events/ scripts. ( The GeanyLua author tells me it is
+a problem with that plugin, and it will be fixed in the 0.6.2 release. :-)
+
+

Added: trunk/geanydebug/THANKS
===================================================================
--- trunk/geanydebug/THANKS	                        (rev 0)
+++ trunk/geanydebug/THANKS	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,20 @@
+Thanks to:
+
+Salvador E. Tropea <set(at)users(dot)sf(dot)net>
+  Author of the libmigdb library. ( This project doesn't use any code from
+  libmigdb, but his project made me believe such a thing was even possible. )
+
+
+Enrico Troeger <enrico(dot)troeger(at)uvena(dot)de>
+  Geany IDE author.
+
+
+Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+  Chief architect of the Geany plugin API.
+
+
+Yura Siamashka yurand2(at)gmail(dot)com
+  Initial autotools scripts ( adapted from the geanyvc plugin. )
+  and improvements to INSTALL instructions.
+
+

Added: trunk/geanydebug/autogen.sh
===================================================================
--- trunk/geanydebug/autogen.sh	                        (rev 0)
+++ trunk/geanydebug/autogen.sh	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,165 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+DIE=0
+
+if [ -n "$GNOME2_DIR" ]; then
+	ACLOCAL_FLAGS="-I $GNOME2_DIR/share/aclocal $ACLOCAL_FLAGS"
+	LD_LIBRARY_PATH="$GNOME2_DIR/lib:$LD_LIBRARY_PATH"
+	PATH="$GNOME2_DIR/bin:$PATH"
+	export PATH
+	export LD_LIBRARY_PATH
+fi
+
+(test -f $srcdir/configure.in) || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+    echo " top-level package directory"
+    exit 1
+}
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: You must have \`autoconf' installed."
+  echo "Download the appropriate package for your distribution,"
+  echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+  DIE=1
+}
+
+(grep "^AC_PROG_INTLTOOL" $srcdir/configure.in >/dev/null) && {
+  (intltoolize --version) < /dev/null > /dev/null 2>&1 || {
+    echo 
+    echo "**Error**: You must have \`intltool' installed."
+    echo "You can get it from:"
+    echo "  ftp://ftp.gnome.org/pub/GNOME/"
+    DIE=1
+  }
+}
+
+(grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.in >/dev/null) && {
+  (xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || {
+    echo
+    echo "**Error**: You must have \`xml-i18n-toolize' installed."
+    echo "You can get it from:"
+    echo "  ftp://ftp.gnome.org/pub/GNOME/"
+    DIE=1
+  }
+}
+
+(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && {
+  (libtool --version) < /dev/null > /dev/null 2>&1 || {
+    echo
+    echo "**Error**: You must have \`libtool' installed."
+    echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/"
+    DIE=1
+  }
+}
+
+(grep "^AM_GLIB_GNU_GETTEXT" $srcdir/configure.in >/dev/null) && {
+  (grep "sed.*POTFILES" $srcdir/configure.in) > /dev/null || \
+  (glib-gettextize --version) < /dev/null > /dev/null 2>&1 || {
+    echo
+    echo "**Error**: You must have \`glib' installed."
+    echo "You can get it from: ftp://ftp.gtk.org/pub/gtk"
+    DIE=1
+  }
+}
+
+(automake --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: You must have \`automake' installed."
+  echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/"
+  DIE=1
+  NO_AUTOMAKE=yes
+}
+
+
+# if no automake, don't bother testing for aclocal
+test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: Missing \`aclocal'.  The version of \`automake'"
+  echo "installed doesn't appear recent enough."
+  echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/"
+  DIE=1
+}
+
+if test "$DIE" -eq 1; then
+  exit 1
+fi
+
+if test -z "$*"; then
+  echo "**Warning**: I am going to run \`configure' with no arguments."
+  echo "If you wish to pass any to it, please specify them on the"
+  echo \`$0\'" command line."
+  echo
+fi
+
+case $CC in
+xlc )
+  am_opt=--include-deps;;
+esac
+
+for coin in `find $srcdir -path $srcdir/CVS -prune -o -name configure.in -print`
+do 
+  dr=`dirname $coin`
+  if test -f $dr/NO-AUTO-GEN; then
+    echo skipping $dr -- flagged as no auto-gen
+  else
+    echo processing $dr
+    ( cd $dr
+
+      aclocalinclude="$ACLOCAL_FLAGS"
+
+      if grep "^AM_GLIB_GNU_GETTEXT" configure.in >/dev/null; then
+	echo "Creating $dr/aclocal.m4 ..."
+	test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
+	echo "Running glib-gettextize...  Ignore non-fatal messages."
+	echo "no" | glib-gettextize --force --copy
+	echo "Making $dr/aclocal.m4 writable ..."
+	test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+      fi
+      if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then
+        echo "Running intltoolize..."
+	intltoolize --copy --force --automake
+      fi
+      if grep "^AM_PROG_XML_I18N_TOOLS" configure.in >/dev/null; then
+        echo "Running xml-i18n-toolize..."
+	xml-i18n-toolize --copy --force --automake
+      fi
+      if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then
+	if test -z "$NO_LIBTOOLIZE" ; then 
+	  echo "Running libtoolize..."
+	  libtoolize --force --copy
+	fi
+      fi
+      if grep "^AC_PROG_LIBTOOL" configure.in >/dev/null; then
+	if test -z "$NO_LIBTOOLIZE" ; then 
+	  echo "Running libtoolize..."
+	  libtoolize --force --copy
+	fi
+      fi
+      echo "Running aclocal $aclocalinclude ..."
+      aclocal $aclocalinclude
+      if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then
+	echo "Running autoheader..."
+	autoheader
+      fi
+      echo "Running automake --gnu $am_opt ..."
+      automake --add-missing --gnu $am_opt
+      echo "Running autoconf ..."
+      autoconf
+    )
+  fi
+done
+
+conf_flags="--enable-maintainer-mode"
+
+if test x$NOCONFIGURE = x; then
+  echo Running $srcdir/configure $conf_flags "$@" ...
+  $srcdir/configure $conf_flags "$@" \
+  && echo Now type \`make\' to compile. || exit 1
+else
+  echo Skipping configure process.
+fi


Property changes on: trunk/geanydebug/autogen.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/geanydebug/configure.in
===================================================================
--- trunk/geanydebug/configure.in	                        (rev 0)
+++ trunk/geanydebug/configure.in	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,73 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT([geanydebug], [0.1], [yurand2 at gmail.com])
+AM_INIT_AUTOMAKE([1.9 foreign])
+
+AM_CONFIG_HEADER(config.h)
+
+AC_PROG_CC
+
+AC_DISABLE_STATIC
+AM_PROG_LIBTOOL
+LIBTOOL="$LIBTOOL --silent"
+
+AC_PROG_INSTALL
+AC_PROG_INTLTOOL
+
+
+# checking for Geany
+PKG_CHECK_MODULES(GEANY, [geany >= 0.15])
+AC_SUBST(GTK_CFLAGS)
+AC_SUBST(GTK_LIBS)
+
+GEANY_VERSION=`$PKG_CONFIG --modversion geany`
+GTK_VERSION=`$PKG_CONFIG --modversion gtk+-2.0`
+
+
+# i18n
+GETTEXT_PACKAGE=geanydebug
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package.])
+
+ALL_LINGUAS="`sed -e '/^#/d' $srcdir/po/LINGUAS`" # take all languages found in file po/LINGUAS
+
+AM_GLIB_GNU_GETTEXT
+# workaround for intltool bug (http://bugzilla.gnome.org/show_bug.cgi?id=490845)
+if test "x$MSGFMT" = "xno"; then
+	AC_MSG_ERROR([msgfmt not found. Please install the gettext package.])
+fi
+
+# intltool hack to define install_sh on Debian/Ubuntu systems
+if test "x$install_sh" = "x"; then
+	install_sh="`pwd`/install-sh"
+	AC_SUBST(install_sh)
+fi
+
+# get the plugin installed at the correct location for Geany
+# TODO find a way to NOT override --libdir command line option if given
+libdir="`$PKG_CONFIG --variable=libdir geany`/geany"
+
+dnl unittests
+PKG_CHECK_MODULES([CHECK], [check >= 0.9.4], [
+AC_SUBST(CHECK_CFLAGS)
+AC_SUBST(CHECK_LIBS)
+AM_CONDITIONAL(UNITTESTS, true)
+], [
+AM_CONDITIONAL(UNITTESTS, false)
+])
+
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+tests/Makefile
+po/Makefile.in
+])
+
+echo "----------------------------------------"
+echo "Install geanydebug in              : ${libdir}"
+echo "Using Geany version                : ${GEANY_VERSION}"
+echo "Using GTK version                  : ${GTK_VERSION}"
+echo ""
+echo "Configuration is done OK."
+echo ""

Added: trunk/geanydebug/indent-all.sh
===================================================================
--- trunk/geanydebug/indent-all.sh	                        (rev 0)
+++ trunk/geanydebug/indent-all.sh	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,4 @@
+#!/bin/sh
+indent -bli0 -i8 -cli8 -npcs -l100 src/*.c src/*.h
+rm src/*~
+


Property changes on: trunk/geanydebug/indent-all.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/geanydebug/makefile.win32
===================================================================
--- trunk/geanydebug/makefile.win32	                        (rev 0)
+++ trunk/geanydebug/makefile.win32	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,63 @@
+# Running make creates config.h then calls the sub makefiles.
+#
+# Other targets are:
+#	deps: delete the dependencies so they are regenerated on next make
+#	clean: clean all generated files
+#
+# localwin32.mk is an optional file to override make variables.
+# Use localwin32.mk instead of editing variables as it is included in sub
+# makefiles.
+# localwin32.mk to set PREFIX instead of the default C:\libs
+# For MSYS use localwin32.mk to set CP and RM.
+# By default this will work in a Windows command prompt.
+
+CC = gcc
+CP = copy
+RM = del
+PREFIX = C:/libs
+GEANY_SRC = ../geany
+TARGET = geanydebug.dll
+.SUFFIXES: .c .o
+-include localwin32.mk
+
+VPATH = src
+
+OBJS =	insert_object_here.o
+INCLUDEDIRS=  -I. -I.. \
+              -I$(GEANY_SRC) \
+              -I$(GEANY_SRC)/src \
+              -I$(GEANY_SRC)/plugins \
+              -I$(GEANY_SRC)/tagmanager/include \
+              -I$(GEANY_SRC)/scintilla/include \
+              -I$(PREFIX)/include/gtk-2.0 \
+              -I$(PREFIX)/lib/gtk-2.0/include \
+              -I$(PREFIX)/include/atk-1.0 \
+              -I$(PREFIX)/include/pango-1.0 \
+              -I$(PREFIX)/include/cairo \
+              -I$(PREFIX)/include/glib-2.0 \
+              -I$(PREFIX)/lib/glib-2.0/include \
+              -I$(PREFIX)/include/gettext \
+              -I$(PREFIX)/include
+ALL_GTK_LIBS= \
+	-L"$(PREFIX)/lib" \
+	-lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangowin32-1.0 -lgdi32 \
+	-lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lglib-2.0 -lintl -liconv
+CCFLAGS=-Wall -O2 -mms-bitfields -DHAVE_CONFIG_H
+
+
+all: $(TARGET)
+
+deps.mak:
+	$(CC) -MM $(CCFLAGS) $(INCLUDEDIRS) src/*.c >deps.mak
+
+.c.o:
+	$(CC) $(CCFLAGS) $(INCLUDEDIRS) -c $<
+
+$(TARGET): $(OBJS) deps.mak
+	$(CC) -shared $(OBJS) $(ALL_GTK_LIBS) -o $(TARGET)
+
+clean:
+	-$(RM) deps.mak *.o *.dll
+
+# Generate header dependencies with "make deps.mak"
+include deps.mak

Added: trunk/geanydebug/po/.gitignore
===================================================================
--- trunk/geanydebug/po/.gitignore	                        (rev 0)
+++ trunk/geanydebug/po/.gitignore	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+Makefile.in.in
+POTFILES
+*.gmo
+*.pot
+stamp-it

Added: trunk/geanydebug/po/LINGUAS
===================================================================
--- trunk/geanydebug/po/LINGUAS	                        (rev 0)
+++ trunk/geanydebug/po/LINGUAS	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,2 @@
+# set of available languages (in alphabetic order)
+

Added: trunk/geanydebug/po/POTFILES.in
===================================================================
--- trunk/geanydebug/po/POTFILES.in	                        (rev 0)
+++ trunk/geanydebug/po/POTFILES.in	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,19 @@
+# List of source files containing translatable strings.
+
+src/gdb-io-break.c
+src/gdb-io-envir.c
+src/gdb-io-frame.c
+src/gdb-io-priv.h
+src/gdb-io-read.c
+src/gdb-io-run.c
+src/gdb-io-stack.c
+src/gdb-io.h
+src/gdb-lex.c
+src/gdb-lex.h
+src/gdb-ui-break.c
+src/gdb-ui-envir.c
+src/gdb-ui-frame.c
+src/gdb-ui-locn.c
+src/gdb-ui-main.c
+src/gdb-ui.h
+src/geanydebug.c

Added: trunk/geanydebug/po/POTFILES.skip
===================================================================
--- trunk/geanydebug/po/POTFILES.skip	                        (rev 0)
+++ trunk/geanydebug/po/POTFILES.skip	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1 @@
+# List of source files containing translatable strings but should be ignored.

Added: trunk/geanydebug/src/Makefile.am
===================================================================
--- trunk/geanydebug/src/Makefile.am	                        (rev 0)
+++ trunk/geanydebug/src/Makefile.am	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,28 @@
+
+lib_LTLIBRARIES = geanydebug.la
+geanydebug_la_SOURCES = gdb-io-break.c \
+    gdb-io-envir.c \
+    gdb-io-frame.c \
+    gdb-io-priv.h \
+    gdb-io-read.c \
+    gdb-io-run.c \
+    gdb-io-stack.c \
+    gdb-io.h \
+    gdb-lex.c \
+    gdb-lex.h \
+    gdb-ui-break.c \
+    gdb-ui-envir.c \
+    gdb-ui-frame.c \
+    gdb-ui-locn.c \
+    gdb-ui-main.c \
+    gdb-ui.h \
+    geanydebug.c
+
+geanydebug_la_LDFLAGS = -module -avoid-version
+geanydebug_la_LIBADD  = @GEANY_LIBS@  $(INTLLIBS)
+
+bin_PROGRAMS = ttyhelper
+ttyhelper_SOURCES = ttyhelper.c
+
+AM_CFLAGS = @GEANY_CFLAGS@ -DLOCALEDIR=\""$(localedir)"\"
+

Added: trunk/geanydebug/src/gdb-io-break.c
===================================================================
--- trunk/geanydebug/src/gdb-io-break.c	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io-break.c	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,312 @@
+
+/*
+ * gdb-io-break.c - Breakpoint management functions for GDB wrapper library. 
+ *
+ * See the file "gdb-io.h" for license information.
+ *
+ */
+
+
+#include <string.h>
+#include <glib.h>
+#include "gdb-io-priv.h"
+
+
+static GdbListFunc gdbio_break_list_func = NULL;
+
+static GSList *breakpoint_list = NULL;
+
+
+static void
+free_breakpoint_list()
+{
+	GSList *p;
+	for (p = breakpoint_list; p; p = p->next)
+	{
+		GdbBreakPointInfo *bpi = p->data;
+		if (bpi)
+		{
+			g_free(bpi->addr);
+			g_free(bpi->disp);
+			g_free(bpi->enabled);
+			g_free(bpi->file);
+			g_free(bpi->fullname);
+			g_free(bpi->func);
+			g_free(bpi->line);
+			g_free(bpi->number);
+			g_free(bpi->times);
+			g_free(bpi->type);
+			g_free(bpi->what);
+			g_free(bpi->cond);
+			g_free(bpi->ignore);
+			g_free(bpi);
+		}
+	}
+	g_slist_free(breakpoint_list);
+	breakpoint_list = NULL;
+}
+
+
+
+#define populate(rec, hash, key) \
+  rec->key=gdblx_lookup_string(hash, #key""); \
+  if (rec->key) {rec->key=g_strdup(rec->key);}
+
+
+
+static void
+breakpoint_cb(gpointer data, gpointer user_data)
+{
+	GdbLxValue *v = (GdbLxValue *) data;
+	if (v && (v->type == vt_HASH) && (v->hash))
+	{
+		GHashTable *bkpt = v->hash;
+		if (bkpt)
+		{
+			GdbBreakPointInfo *bpi = g_new0(GdbBreakPointInfo, 1);
+			populate(bpi, bkpt, addr);
+			populate(bpi, bkpt, disp);
+			populate(bpi, bkpt, enabled);
+			populate(bpi, bkpt, file);
+			populate(bpi, bkpt, fullname);
+			populate(bpi, bkpt, func);
+			populate(bpi, bkpt, line);
+			populate(bpi, bkpt, number);
+			populate(bpi, bkpt, times);
+			populate(bpi, bkpt, type);
+			populate(bpi, bkpt, what);
+			populate(bpi, bkpt, cond);
+			populate(bpi, bkpt, ignore);
+			breakpoint_list = g_slist_append(breakpoint_list, bpi);
+		}
+	}
+}
+
+
+static void
+parse_break_list(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HTAB(h, BreakpointTable);
+	gdbio_pop_seq(seq);
+	if (BreakpointTable && gdbio_break_list_func)
+	{
+		HLST(BreakpointTable, body);
+		if (body)
+		{
+			free_breakpoint_list();
+			g_slist_foreach(body, breakpoint_cb, NULL);
+			gdbio_break_list_func(breakpoint_list);
+			free_breakpoint_list();
+		}
+		else
+		{
+			gdbio_break_list_func(NULL);
+		}
+	}
+	if (h)
+		g_hash_table_destroy(h);
+}
+
+
+
+void
+gdbio_show_breaks(GdbListFunc func)
+{
+	gdbio_break_list_func = func;
+	if (func)
+	{
+		gdbio_send_seq_cmd(parse_break_list, "-break-list\n");
+	}
+}
+
+
+
+static void
+added_break(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		HTAB(h, bkpt);
+		if (bkpt)
+		{
+			HSTR(bkpt, file);
+			HSTR(bkpt, line);
+			HSTR(bkpt, func);
+			HSTR(bkpt, number);
+			if (func)
+			{
+				gdbio_info_func("Added breakpoint #%s in %s() at %s:%s\n", number,
+						func, file, line);
+			}
+			else
+			{
+				gdbio_info_func("Added breakpoint #%s at %s:%s\n", number, file,
+						line);
+			}
+
+		}
+		else
+		{
+			HTAB(h, wpt);
+			if (wpt)
+			{
+				HSTR(wpt, exp);
+				HSTR(wpt, number);
+				gdbio_info_func("Added write watchpoint #%s for %s\n", number, exp);
+			}
+			else
+			{
+				HTAB(h, hw_awpt);
+				if (hw_awpt)
+				{
+					HSTR(hw_awpt, exp);
+					HSTR(hw_awpt, number);
+					gdbio_info_func("Added read/write watchpoint #%s for %s\n",
+							number, exp);
+				}
+				else
+				{
+					HTAB(h, hw_rwpt);
+					if (hw_rwpt)
+					{
+						HSTR(hw_rwpt, exp);
+						HSTR(hw_rwpt, number);
+						gdbio_info_func
+							("Added read watchpoint #%s for %s\n",
+							 number, exp);
+					}
+				}
+			}
+		}
+		g_hash_table_destroy(h);
+	}
+	if (gdbio_break_list_func)
+	{
+		gdbio_show_breaks(gdbio_break_list_func);
+	}
+}
+
+/* opt is "-r" (read) or "-a" (r/w) or NULL or empty (write) */
+void
+gdbio_add_watch(GdbListFunc func, const gchar * option, const gchar * varname)
+{
+	gdbio_break_list_func = func;
+	gdbio_send_seq_cmd(added_break, "-break-watch %s %s\n", option ? option : "", varname);
+}
+
+
+
+void
+gdbio_add_break(GdbListFunc func, const gchar * filename, const gchar * locn)
+{
+	gdbio_break_list_func = func;
+	if (filename && *filename)
+	{
+		gdbio_send_seq_cmd(added_break, "-break-insert %s:%s\n", filename, locn);
+	}
+	else
+	{
+		gdbio_send_seq_cmd(added_break, "-break-insert %s\n", locn);
+	}
+}
+
+
+static void
+deleted_break(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		g_hash_table_destroy(h);
+		gdbio_info_func("Watch/breakpoint deleted.\n");
+	}
+	if (gdbio_break_list_func)
+	{
+		gdbio_show_breaks(gdbio_break_list_func);
+	}
+}
+
+
+
+static void
+toggled_break(gint seq, gchar ** list, gchar * resp)
+{
+	gdbio_pop_seq(seq);
+	if (strncmp(resp, "^error", 6) == 0)
+	{
+		if (resp[6] == ',')
+		{
+			GHashTable *h = gdblx_parse_results(resp + 7);
+			HSTR(h, msg);
+
+			if (msg)
+			{
+				gchar *tmp =
+					g_strconcat("Failed to toggle breakpoint -\n", msg, NULL);
+				gdbio_error_func(tmp);
+				if (tmp)
+				{
+					g_free(tmp);
+				}
+			}
+			else
+			{
+			}
+			if (h)
+			{
+				g_hash_table_destroy(h);
+			}
+		}
+	}
+	else
+	{
+		gdbio_info_func("Watch/breakpoint toggled.\n");
+	}
+}
+
+
+
+static void
+edited_break(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		g_hash_table_destroy(h);
+		gdbio_info_func("Watch/breakpoint modified.\n");
+	}
+}
+
+
+void
+gdbio_delete_break(GdbListFunc func, const gchar * number)
+{
+	gdbio_break_list_func = func;
+	gdbio_send_seq_cmd(deleted_break, "-break-delete %s\n", number);
+}
+
+
+void
+gdbio_enable_break(const gchar * number, gboolean enabled)
+{
+	gdbio_send_seq_cmd(toggled_break, "-break-%s %s\n", enabled ? "enable" : "disable", number);
+}
+
+
+void
+gdbio_ignore_break(const gchar * number, const gchar * times)
+{
+	gdbio_send_seq_cmd(edited_break, "-break-after %s %s\n", number, times);
+}
+
+
+void
+gdbio_break_cond(const gchar * number, const gchar * expr)
+{
+	gdbio_send_seq_cmd(edited_break, "-break-condition %s %s\n", number, expr);
+}

Added: trunk/geanydebug/src/gdb-io-envir.c
===================================================================
--- trunk/geanydebug/src/gdb-io-envir.c	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io-envir.c	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,182 @@
+
+/*
+ * gdb-io-envir.c - Environment settings for GDB wrapper library. 
+ *
+ * See the file "gdb-io.h" for license information.
+ *
+ */
+
+
+#include <string.h>
+#include <glib.h>
+#include "gdb-io-priv.h"
+
+
+static GdbEnvironFunc gdbio_environ_func = NULL;
+
+static GdbEnvironInfo env_info = { NULL, NULL, NULL, NULL };
+
+
+static void
+free_env_info()
+{
+	g_free(env_info.cwd);
+	g_free(env_info.path);
+	g_free(env_info.args);
+	g_free(env_info.dirs);
+	memset(&env_info, '\0', sizeof(env_info));
+}
+
+
+
+static gchar *
+unquote(gchar * quoted)
+{
+	gint len = quoted ? strlen(quoted) : 0;
+	if (len && (quoted[0] == '"') && (quoted[len - 1] == '"'))
+	{
+		gchar *tmp = g_strndup(quoted + 1, len - 2);
+		gchar *rv = g_strcompress(tmp);
+		g_free(tmp);
+		return rv;
+	}
+	else
+		return NULL;
+}
+
+
+
+static void
+get_env_args(gint seq, gchar ** list, gchar * resp)
+{
+	gchar *args;
+	gint i;
+	gdbio_pop_seq(seq);
+	for (i = 0; list[i]; i++)
+	{
+		if (strncmp(list[i], "~\"", 2) == 0)
+		{
+			args = unquote(list[i] + 1);
+			if (args && *args)
+			{
+				g_strstrip(args);
+				gchar *quote = strchr(args, '"');
+				if (quote)
+				{
+					memmove(args, quote + 1, strlen(quote));
+					quote = strrchr(args, '"');
+					if (quote && g_str_equal(quote, "\"."))
+					{
+						*quote = '\0';
+						break;
+					}
+				}
+			}
+			g_free(args);
+			args = NULL;
+		}
+	}
+	env_info.args = args;
+	if (gdbio_environ_func)
+	{
+		gdbio_environ_func(&env_info);
+	}
+}
+
+
+
+static void
+get_env_dirs(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HSTR(h, source_path);
+	gdbio_pop_seq(seq);
+	if (source_path)
+	{
+		gchar *p;
+		env_info.dirs = g_strdup(source_path);
+		p = strstr(env_info.dirs, "$cdir:$cwd");
+		if (p)
+		{
+			memmove(p, p + 10, strlen(p + 10) + 1);
+		}
+		p = strchr(env_info.dirs, '\0');
+		if (p)
+		{
+			while (p > env_info.dirs)
+			{
+				p--;
+				if (*p == ':')
+				{
+					*p = '\0';
+				}
+				else
+				{
+					break;
+				}
+			}
+		}
+	}
+	else
+	{
+		gdbio_info_func("Failed to retrieve source search path setting from GDB.");
+//    gdblx_dump_table(h);
+	}
+	if (h)
+		g_hash_table_destroy(h);
+	gdbio_send_seq_cmd(get_env_args, "show args\n");
+}
+
+
+static void
+get_env_path(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HSTR(h, path);
+	gdbio_pop_seq(seq);
+	if (path)
+	{
+		env_info.path = g_strdup(path);
+	}
+	else
+	{
+		gdbio_info_func("Failed to retrieve executable search path setting from GDB.");
+//    gdblx_dump_table(h);
+	}
+	if (h)
+		g_hash_table_destroy(h);
+	gdbio_send_seq_cmd(get_env_dirs, "-environment-directory\n");
+}
+
+
+static void
+get_env_cwd(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HSTR(h, cwd);
+	gdbio_pop_seq(seq);
+	free_env_info();
+	if (cwd)
+	{
+		env_info.cwd = g_strdup(cwd);
+	}
+	else
+	{
+		gdbio_info_func("Failed to retrieve working directory setting from GDB.");
+//    gdblx_dump_table(h);
+	}
+	if (h)
+		g_hash_table_destroy(h);
+	gdbio_send_seq_cmd(get_env_path, "-environment-path\n");
+}
+
+
+void
+gdbio_get_env(GdbEnvironFunc func)
+{
+	gdbio_environ_func = func;
+	if (func)
+	{
+		gdbio_send_seq_cmd(get_env_cwd, "-environment-pwd\n");
+	}
+}

Added: trunk/geanydebug/src/gdb-io-frame.c
===================================================================
--- trunk/geanydebug/src/gdb-io-frame.c	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io-frame.c	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,542 @@
+
+/*
+ * gdb-io-frame.c - Stack frame information functions for GDB wrapper library. 
+ *
+ * See the file "gdb-io.h" for license information.
+ *
+ */
+
+
+#include <string.h>
+#include <glib.h>
+
+#include "gdb-io-priv.h"
+
+
+static GdbFrameFunc gdbio_locals_func = NULL;
+
+static GSList *locals_list = NULL;
+static GSList **which_list = NULL;
+
+static gint locals_index = 0;
+static gint args_index = 0;
+static gint *which_index = NULL;
+
+static void var_created(gint seq, gchar ** list, gchar * resp);
+static void got_varlist(gint seq, gchar ** list, gchar * resp);
+
+typedef enum _FrameProcState
+{
+	fpBegin,
+	fpGotLocals,
+	fpGotArgs
+} FrameProcState;
+
+
+static FrameProcState state = fpBegin;
+static GdbFrameInfo current_frame;
+
+
+
+static void
+gdbio_free_var(GdbVar * v)
+{
+	if (v)
+	{
+		g_free(v->type);
+		g_free(v->name);
+		g_free(v->value);
+		g_free(v->numchild);
+		g_free(v);
+	}
+}
+
+
+void
+gdbio_free_var_list(GSList * args)
+{
+	GSList *p;
+	for (p = args; p; p = p->next)
+	{
+		gdbio_free_var((GdbVar *) p->data);
+	}
+	g_slist_free(args);
+}
+
+
+
+static void
+free_lists()
+{
+	gdbio_free_var_list(locals_list);
+	locals_list = NULL;
+	locals_index = 0;
+	args_index = 0;
+	which_list = &locals_list;
+	which_index = &locals_index;
+	state = fpBegin;
+	g_free(current_frame.func);
+	g_free(current_frame.filename);
+	gdbio_free_var_list(current_frame.args);
+	memset(&current_frame, 0, sizeof(current_frame));
+}
+
+static void
+get_arglist()
+{
+	which_list = &current_frame.args;
+	which_index = &args_index;
+	gdbio_send_seq_cmd(got_varlist, "-stack-list-arguments 1 %s %s\n",
+			   current_frame.level, current_frame.level);
+}
+
+
+static void
+create_var(gchar * varname)
+{
+	gdbio_send_seq_cmd(var_created, "-var-create x%s * %s\n", varname, varname);
+}
+
+
+static void
+var_deleted(gint seq, gchar ** list, gchar * resp)
+{
+	gdbio_pop_seq(seq);
+	(*which_index)++;
+	GdbVar *lv = g_slist_nth_data(*which_list, *which_index);
+	if (lv)
+	{
+		create_var(lv->name);
+	}
+	else
+	{
+		if (state == fpBegin)
+		{
+			state = fpGotLocals;
+			get_arglist();
+		}
+		else
+		{
+			if (gdbio_locals_func)
+			{
+				gdbio_locals_func(&current_frame, locals_list);
+			}
+			free_lists();
+		}
+	}
+}
+
+
+
+static void
+delete_var(gchar * varname)
+{
+	gdbio_send_seq_cmd(var_deleted, "-var-delete x%s\n", varname);
+}
+
+
+
+static gchar *
+fmt_val(gchar * value)
+{
+	gchar buf[256];
+	if (!value)
+		return g_strdup("0");
+	if (strlen(value) < sizeof(buf))
+	{
+		return g_strdup(value);
+	}
+	strncpy(buf, value, sizeof(buf) - 1);
+	buf[sizeof(buf) - 1] = '\0';
+	return g_strdup_printf("%s...%s", buf, strchr(buf, '"') ? "\"" : "");
+}
+
+
+
+static void
+var_created(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HSTR(h, type);
+	HSTR(h, value);
+	HSTR(h, numchild);
+	gdbio_pop_seq(seq);
+	if (type)
+	{
+		GdbVar *lv = g_slist_nth_data(*which_list, *which_index);
+		if (lv)
+		{
+			lv->type = g_strdup(type ? type : "int");
+			lv->value = fmt_val(value);
+			lv->numchild = g_strdup(numchild ? numchild : "0");
+		}
+		delete_var(lv->name);
+	}
+	if (h)
+		g_hash_table_destroy(h);
+}
+
+
+
+void
+got_varlist(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	GSList *hlist = NULL;
+	HLST(h, locals);
+	HLST(h, stack_args);
+	gdbio_pop_seq(seq);
+	if (state == fpBegin)
+	{
+		hlist = locals;
+	}
+	else
+	{
+		GdbLxValue *v = stack_args->data;
+		if (v && (v->type == vt_HASH))
+		{
+			HLST(v->hash, args);
+			if (args)
+			{
+				hlist = args;
+			}
+		}
+	}
+	if (hlist)
+	{
+		GSList *p;
+		GdbVar *lv;
+		for (p = hlist; p; p = p->next)
+		{
+			GdbLxValue *v = p->data;
+			if (v && (v->type == vt_HASH) && v->hash)
+			{
+				HSTR(v->hash, name);
+				if (name)
+				{
+					GdbVar *lv = g_new0(GdbVar, 1);
+					lv->name = g_strdup(name);
+					*which_list = g_slist_append(*which_list, lv);
+				}
+			}
+		}
+		lv = g_slist_nth_data(*which_list, *which_index);
+		if (lv)
+		{
+			create_var(lv->name);
+		}
+	}
+	else
+	{
+		if (state == fpBegin)
+		{
+			state = fpGotLocals;
+			get_arglist();
+		}
+		else
+		{
+			if (gdbio_locals_func)
+			{
+				gdbio_locals_func(&current_frame, locals_list);
+			}
+		}
+	}
+	if (h)
+		g_hash_table_destroy(h);
+}
+
+
+
+
+
+static void
+got_current_level(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HTAB(h, frame);
+	gdbio_pop_seq(seq);
+	if (frame)
+	{
+		HSTR(frame, level);
+		if (level)
+		{
+			HSTR(frame, addr);
+			HSTR(frame, func);
+			HSTR(frame, file);
+			HSTR(frame, fullname);
+			HSTR(frame, line);
+			strncpy(current_frame.level, level, sizeof(current_frame.level) - 1);
+			strncpy(current_frame.addr, addr ? addr : "",
+				sizeof(current_frame.addr) - 1);
+			strncpy(current_frame.line, line ? line : "",
+				sizeof(current_frame.line) - 1);
+			current_frame.filename = g_strdup(fullname ? fullname : file ? file : "");
+			current_frame.func = g_strdup(func ? func : "");
+		}
+	}
+	if (h)
+		g_hash_table_destroy(h);
+	gdbio_send_seq_cmd(got_varlist, "-stack-list-locals 1\n");
+}
+
+
+static void
+set_current_level(gint seq, gchar ** list, gchar * resp)
+{
+	gdbio_pop_seq(seq);
+	gdbio_send_seq_cmd(got_current_level, "-stack-info-frame\n");
+}
+
+void
+gdbio_show_locals(GdbFrameFunc func, gchar * level)
+{
+	free_lists();
+	gdbio_locals_func = func;
+	gdbio_send_seq_cmd(set_current_level, "-stack-select-frame %s\n", level);
+}
+
+
+
+
+static gpointer
+qpop(GQueue ** q)
+{
+	gpointer p = NULL;
+	if (*q)
+	{
+		p = g_queue_pop_head(*q);
+		if (g_queue_get_length(*q) == 0)
+		{
+			g_queue_free(*q);
+			*q = NULL;
+		}
+	}
+	return p;
+}
+
+static void
+qpush(GQueue ** q, gpointer p)
+{
+	if (p)
+	{
+		if (!*q)
+		{
+			*q = g_queue_new();
+		}
+		g_queue_push_head(*q, p);
+	}
+}
+
+static gpointer
+qtop(GQueue * q)
+{
+	return q ? g_queue_peek_head(q) : NULL;
+}
+
+
+
+/*
+static gpointer qnth(GQueue*q, gint n)
+{
+  return q?g_queue_peek_nth(q, n):NULL;
+}
+
+static gint qlen(GQueue*q)
+{
+  return q?g_queue_get_length(q):0;
+}
+*/
+
+
+static GQueue *obj_list_queue = NULL;
+static void
+push_list(GSList * p)
+{
+	qpush(&obj_list_queue, p);
+}
+static void
+pop_list()
+{
+	gdbio_free_var_list(qpop(&obj_list_queue));
+}
+static GSList *
+top_list()
+{
+	return qtop(obj_list_queue);
+}
+
+
+static GQueue *obj_var_queue = NULL;
+static void
+push_var(GdbVar * p)
+{
+	qpush(&obj_var_queue, p);
+}
+static void
+pop_var()
+{
+	gdbio_free_var(qpop(&obj_var_queue));
+}
+static GdbVar *
+top_var()
+{
+	return qtop(obj_var_queue);
+}
+
+
+
+
+//static GdbObjectFunc gdbio_object_list_func=NULL;
+
+static GQueue *obj_func_queue = NULL;
+static void
+push_func(GdbObjectFunc p)
+{
+	qpush(&obj_func_queue, p);
+}
+static void
+pop_func()
+{
+	qpop(&obj_func_queue);
+}
+static GdbObjectFunc
+top_func()
+{
+	return qtop(obj_func_queue);
+}
+
+
+
+
+static void
+done_top()
+{
+	pop_var();
+	pop_list();
+//  pop_name();
+	pop_func();
+}
+
+
+
+static void
+object_deleted(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		if (top_func() && top_var() && top_list())
+		{
+			top_func()(top_var(), top_list());
+		}
+		done_top();
+		g_hash_table_destroy(h);
+	}
+}
+
+
+
+static GdbVar *
+hash_val_to_var(GHashTable * h)
+{
+	HSTR(h, name);
+	if (name)
+	{
+		GdbVar *var = g_new0(GdbVar, 1);
+		HSTR(h, type);
+		HSTR(h, value);
+		HSTR(h, numchild);
+		var->name = g_strdup(name + 1);
+		var->type = g_strdup(type ? type : "int");
+		var->value = fmt_val(value);
+		var->numchild = g_strdup(numchild ? numchild : "0");
+		return var;
+	}
+	return NULL;
+}
+
+
+#define MAX_ITEMS 1024
+
+static GSList *
+hash_list_to_var_list(GSList * hlist)
+{
+	GSList *vlist = NULL;
+	GSList *p;
+	gint i;
+	for (p = hlist, i = 0; p; p = p->next, i++)
+	{
+		GdbLxValue *hv = p->data;
+		if (hv && (hv->type == vt_HASH) && hv->hash)
+		{
+			GdbVar *var = hash_val_to_var(hv->hash);
+			if (var)
+			{
+				vlist = g_slist_append(vlist, var);
+			}
+		}
+		if (i >= MAX_ITEMS)
+		{
+			GdbVar *var = g_new0(GdbVar, 1);
+			var->type = g_strdup(" ");
+			var->name = g_strdup_printf("* LIST TRUNCATED AT ITEM #%d *", i + 1);
+			var->value = g_strdup(" ");
+			var->numchild = g_strdup("0");
+			vlist = g_slist_append(vlist, var);
+			gdbio_error_func("Field list too long, not all items can be displayed.\n");
+			break;
+		}
+	}
+	return vlist;
+}
+
+
+
+static void
+object_listed(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		HLST(h, children);
+		if (children)
+		{
+			push_list(hash_list_to_var_list(children));
+		}
+		gdbio_send_seq_cmd(object_deleted, "-var-delete x%s\n", top_var()->name);
+		g_hash_table_destroy(h);
+	}
+}
+
+
+
+static void
+object_created(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		HSTR(h, name);
+		if (name)
+		{
+			push_var(hash_val_to_var(h));
+			gdbio_send_seq_cmd(object_listed, "-var-list-children 1 %s\n", name);
+		}
+		g_hash_table_destroy(h);
+	}
+}
+
+
+void
+gdbio_show_object(GdbObjectFunc func, const gchar * varname)
+{
+
+	if (func)
+	{
+		push_func(func);
+		gdbio_send_seq_cmd(object_created, "-var-create x%s * %s\n", varname, varname);
+	}
+}

Added: trunk/geanydebug/src/gdb-io-priv.h
===================================================================
--- trunk/geanydebug/src/gdb-io-priv.h	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io-priv.h	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,95 @@
+
+/*
+ * gdb-io-priv.h - private header for GDB wrapper library. 
+ *
+ * See the file "gdb-io.h" for license information.
+ *
+ */
+
+
+#include "gdb-lex.h"
+#include "gdb-io.h"
+
+
+void gdbio_free_var_list(GSList * args);
+
+
+typedef void (*ResponseHandler) (gint seq, gchar ** lines, gchar * resp);
+
+
+/*
+  Sends a command to GDB, and returns the results to the specified
+  ResponseHandler function.
+*/
+gint gdbio_send_seq_cmd(ResponseHandler func, const gchar * fmt, ...);
+
+
+/* Look up a handler function */
+ResponseHandler gdbio_seq_lookup(gint seq);
+
+
+/*
+  gdbio_pop_seq() removes a handler function from the sequencer.
+  This should (almost) always be called from the associated
+  ResponseHandler function, to avoid filling up the sequencer
+  with stale commands.
+*/
+void gdbio_pop_seq(gint seq);
+
+
+/*
+  Parses the output of GDB and returns it as a hash table,
+  unless the response is an error message, it calls the
+  error handler function and then returns NULL.
+*/
+GHashTable *gdbio_get_results(gchar * resp, gchar ** list);
+
+/*
+Preprocessor sugar for declaring C variables from hash key names, e.g.
+  HSTR(myhash,somevar)
+expands to:
+  gchar *somevar = gdblx_lookup_string ( myhash, "somevar" );
+*/
+#define HSTR(hash,token) gchar* token = gdblx_lookup_string(hash, #token"");
+#define HTAB(hash,token) GHashTable* token = gdblx_lookup_hash(hash, #token"");
+#define HLST(hash,token) GSList* token = gdblx_lookup_list(hash, #token"");
+
+
+#if 0
+#define do_loop()  \
+  while (g_main_context_pending(NULL)) \
+    g_main_context_iteration(NULL,FALSE);
+#else
+#define do_loop() g_main_context_iteration(NULL,FALSE);
+#endif
+
+
+
+
+void gdbio_info_func(gchar * fmt, ...);
+void gdbio_error_func(gchar * fmt, ...);
+void gdbio_do_status(GdbStatus s);
+
+
+void gdbio_target_exited(gchar * reason);
+void gdbio_set_target_pid(GPid pid);
+GPid gdbio_get_target_pid();
+void gdbio_set_running(gboolean running);
+
+/*
+ Max/Min values for sequencer tokens.
+The current values of 100000-999999 allow for 899999 pending commands.
+I can't imagine why you would need more, but if you change this,keep in mind
+that the number of digits for any possible value *must* be exactly SEQ_LEN.
+*/
+
+#define SEQ_MIN 100000
+#define SEQ_MAX 999999
+#define SEQ_LEN 6
+
+
+
+void gdbio_consume_response(GString * recv_buf);
+
+void gdbio_set_starting(gboolean s);
+void gdbio_target_started(gint seq, gchar ** list, gchar * resp);

Added: trunk/geanydebug/src/gdb-io-read.c
===================================================================
--- trunk/geanydebug/src/gdb-io-read.c	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io-read.c	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,810 @@
+/*
+ *
+ * gdb-io-read.c - Output reading functions for GDB wrapper library. 
+ *
+ * See the file "gdb-io.h" for license information.
+ */
+
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <glib.h>
+
+#include "gdb-io-priv.h"
+
+
+
+static GSList *source_files = NULL;
+
+static gboolean starting = FALSE;
+
+
+
+static void
+free_string_list(GSList ** list)
+{
+	GSList *p;
+	for (p = *list; p; p = p->next)
+	{
+		if (p->data)
+		{
+			g_free(p->data);
+		}
+	}
+	*list = NULL;
+}
+
+
+static void
+free_source_list()
+{
+	free_string_list(&source_files);
+}
+
+
+
+static gint
+find_file_and_fullname(gconstpointer data, gconstpointer user_data)
+{
+	GdbLxValue *v = (GdbLxValue *) data;
+	gchar *ref = (gchar *) user_data;
+	HSTR(v->hash, fullname);
+	HSTR(v->hash, file);
+	return (fullname && file
+		&& (g_str_equal(ref, file) || g_str_equal(ref, fullname))) ? 0 : -1;
+}
+
+
+
+static void
+parse_file_list_cb(gpointer data, gpointer user_data)
+{
+	GdbLxValue *v = (GdbLxValue *) data;
+	if (v && (v->type == vt_HASH))
+	{
+		HSTR(v->hash, fullname);
+		HSTR(v->hash, file);
+		if (file && !fullname)
+		{
+			if (g_slist_find_custom((GSList *) user_data, file, find_file_and_fullname))
+			{
+				return;
+			}
+		}
+		if (fullname)
+		{
+			file = fullname;
+		}
+		if (file)
+		{
+			if (!g_slist_find_custom(source_files, file, (GCompareFunc) strcmp))
+			{
+				source_files = g_slist_append(source_files, g_strdup(file));
+			}
+		}
+	}
+}
+
+
+
+static void handle_response_line(gchar * str, gchar ** list);
+
+
+static void
+handle_response_lines(gchar ** list)
+{
+	if (list)
+	{
+		gint i;
+		for (i = 0; list[i]; i++)
+		{
+			handle_response_line(list[i], list);
+		}
+	}
+}
+
+
+
+static gboolean
+response_is_error(gchar * resp, gchar ** list)
+{
+	if (strncmp(resp, "^error", 6) == 0)
+	{
+		handle_response_line(resp, list);
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+#define CHK_RESP_ERR(resp, list) if (response_is_error(resp,list)) { return; }
+
+#define IsDigit g_ascii_isdigit
+
+static void
+parse_process_info(gint seq, gchar ** list, gchar * resp)
+{
+	CHK_RESP_ERR(resp, list);
+	gdbio_pop_seq(seq);
+	if (g_str_equal(resp, "^done"))
+	{
+		gchar *pidstr = strchr(list[0], ' ');
+		if (pidstr)
+		{
+			GPid pid = -1;
+			while (g_ascii_isspace(*pidstr))
+			{
+				pidstr++;
+			}
+			if (IsDigit(*pidstr))
+			{
+				gchar *end = pidstr;
+				while (IsDigit(*end))
+				{
+					end++;
+				}
+				*end = '\0';
+				pid = gdbio_atoi(pidstr);
+				if ((pid > 0) && (!gdbio_get_target_pid()))
+				{
+					gdbio_set_target_pid(pid);
+					gdbio_send_cmd("-exec-continue\n");
+				}
+			}
+		}
+	}
+}
+
+
+GHashTable *
+gdbio_get_results(gchar * resp, gchar ** list)
+{
+	if (strncmp(resp, "^error", 6) == 0)
+	{
+		if (resp[6] == ',')
+		{
+			GHashTable *h = gdblx_parse_results(resp + 7);
+			HSTR(h, msg);
+			gchar *tmp = NULL;
+			if (msg)
+			{
+				if (g_str_equal(msg, "unknown error"))
+				{
+					gint len = g_strv_length(list);
+					if ((len > 1) && list[len - 2] && *list[len - 2])
+					{
+						tmp = list[len - 2];
+						if (tmp[0] == '&')
+						{
+							tmp++;
+						}
+						tmp = g_strcompress(tmp);
+						g_strstrip(tmp);
+						msg = tmp;
+					}
+				}
+				gdbio_error_func(msg);
+				if (tmp)
+				{
+					g_free(tmp);
+				}
+			}
+			if (h)
+			{
+				g_hash_table_destroy(h);
+			}
+		}
+		return NULL;
+	}
+	if (strncmp(resp, "^done,", 6) == 0)
+		return gdblx_parse_results(resp + 6);
+	if (strncmp(resp, "*stopped,", 9) == 0)
+	{
+		gdbio_do_status(GdbStopped);
+		return gdblx_parse_results(resp + 9);
+	}
+	return NULL;
+}
+
+
+
+static void handle_response_line(gchar * str, gchar ** list);
+
+
+void
+gdbio_set_starting(gboolean s)
+{
+	starting = s;
+}
+
+void
+gdbio_target_started(gint seq, gchar ** list, gchar * resp)
+{
+	if ((strncmp(resp, "^error", 6) == 0) && (!gdbio_get_target_pid()))
+	{
+		gdbio_error_func("Error starting target process!\n");
+		gdbio_do_status(GdbFinished);
+	}
+	else
+	{
+		handle_response_lines(list);
+	}
+}
+
+
+
+static void
+set_main_break(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HTAB(h, bkpt);
+	gdbio_pop_seq(seq);
+	if (bkpt)
+	{
+		if (gdblx_check_keyval(bkpt, "number", "1"))
+		{
+			gdbio_do_status(GdbLoaded);
+		}
+	}
+	if (h)
+		g_hash_table_destroy(h);
+}
+
+
+void
+gdbio_parse_file_list(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HLST(h, files);
+	gdbio_pop_seq(seq);
+	if (files)
+	{
+		free_source_list();
+		g_slist_foreach(files, parse_file_list_cb, files);
+		free_source_list();
+		gdbio_send_seq_cmd(set_main_break, "-break-insert _start\n");
+	}
+	else
+	{
+		gdbio_error_func
+			("This executable does not appear to contain the required debugging information.");
+	}
+	if (h)
+		g_hash_table_destroy(h);
+}
+
+
+
+
+
+static gboolean
+do_step_func(GHashTable * h, gchar * reason)
+{
+	HTAB(h, frame);
+	HSTR(frame, fullname);
+	HSTR(frame, line);
+	if (fullname && line)
+	{
+		if (gdbio_setup.step_func)
+		{
+			gchar *p;
+			for (p = reason; *p; p++)
+			{
+				if (*p == '-')
+				{
+					*p = ' ';
+				}
+			}
+			gdbio_setup.step_func(fullname, line, reason);
+		}
+		else
+		{
+			gdbio_info_func("%s:%s", fullname, line);
+		}
+		return TRUE;
+	}
+	else
+	{
+		HSTR(frame, func);
+		if (func)
+		{
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+
+
+#define reason_is(r) (r && reason && g_str_equal(reason, r))
+
+static void
+finish_function(gint seq, gchar ** list, gchar * resp)
+{
+	if (strncmp(resp, "^running", 8) == 0)
+	{
+		gdbio_set_running(TRUE);
+		gdbio_do_status(GdbRunning);
+	}
+	else
+	{
+		GHashTable *h = gdbio_get_results(resp, list);
+		HSTR(h, reason);
+		gdbio_pop_seq(seq);
+		if (reason_is("function-finished"))
+		{
+			gdbio_do_status(GdbStopped);
+			do_step_func(h, reason);
+		}
+		else
+		{
+			handle_response_lines(list);
+		}
+		if (h)
+			g_hash_table_destroy(h);
+	}
+}
+
+
+static void
+return_function(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		do_step_func(h, "returned");
+	}
+	else
+	{
+		handle_response_lines(list);
+	}
+}
+
+
+
+
+static void
+watchpoint_trigger(GHashTable * h, GHashTable * wp, gchar * reason)
+{
+	HTAB(h, value);
+	HSTR(wp, exp);
+	HSTR(wp, number);
+	HSTR(value, new);
+	HSTR(value, old);
+	gchar *readval = gdblx_lookup_string(value, "value");
+	if (new && old)
+	{
+		gdbio_info_func("%s #%s  expression:%s  old-value:%s  new-value:%s\n",
+				reason, number ? number : "?", exp ? exp : "?", old, new);
+	}
+	else
+	{
+		if (old)
+		{
+			gdbio_info_func("%s #%s  expression:%s  value:%s", reason,
+					number ? number : "?", exp ? exp : "?", old);
+		}
+		else
+		{
+			if (new)
+			{
+				gdbio_info_func("%s #%s  expression:%s  value:%s", reason,
+						number ? number : "?", exp ? exp : "?", new);
+			}
+			else
+			{
+				if (readval)
+				{
+					gdbio_info_func("%s #%s  expression:%s  value:%s", reason,
+							number ? number : "?", exp ? exp : "?",
+							readval);
+				}
+				else
+				{
+					gdbio_info_func("%s #%s  expression:%s", reason,
+							number ? number : "?", exp ? exp : "?");
+				}
+			}
+		}
+	}
+}
+
+static gboolean
+handle_results_hash(GHashTable * h, gchar * rectype, gchar ** list)
+{
+	if (g_str_equal(rectype, "^error"))
+	{
+		HSTR(h, msg);
+		gchar *tmp = NULL;
+		if (msg)
+		{
+			if (g_str_equal(msg, "unknown error"))
+			{
+				gint len = g_strv_length(list);
+				if ((len > 1) && list[len - 2] && *list[len - 2])
+				{
+					tmp = list[len - 2];
+					if (tmp[0] == '&')
+					{
+						tmp++;
+					}
+					tmp = g_strcompress(tmp);
+					g_strstrip(tmp);
+					msg = tmp;
+				}
+			}
+			gdbio_error_func(msg);
+			if (tmp)
+			{
+				g_free(tmp);
+			}
+			return TRUE;
+		}
+		else
+			return FALSE;
+	}
+	if (g_str_equal(rectype, "^done"))
+	{
+
+		HTAB(h, frame);
+		if (frame)
+		{
+			HSTR(frame, fullname);
+			HSTR(frame, line);
+			if (fullname && line)
+			{
+				return do_step_func(h, "done");
+			}
+		}
+		return FALSE;
+	}
+	if (g_str_equal(rectype, "*stopped"))
+	{
+		HSTR(h, reason);
+		if (!reason)
+		{
+			return FALSE;
+		}
+		if (reason_is("breakpoint-hit"))
+		{
+			if (gdblx_check_keyval(h, "bkptno", "1"))
+			{
+				gdbio_send_seq_cmd(parse_process_info,
+						   "-interpreter-exec console \"info proc\"\n");
+				return TRUE;
+			}
+			else
+			{
+				return (do_step_func(h, reason));
+			}
+			return FALSE;
+		}
+		gdbio_set_running(FALSE);
+		if (reason_is("signal-received"))
+		{
+			HSTR(h, signal_name);
+			HSTR(h, signal_meaning);
+			HSTR(h, thread_id);
+			HTAB(h, frame);
+			HSTR(frame, func);
+			HSTR(frame, file);
+			HSTR(frame, fullname);
+			HSTR(frame, line);
+			HSTR(frame, addr);
+			HSTR(frame, from);
+			HLST(frame, args);
+			if (!fullname)
+			{
+				fullname = "??";
+			}
+			if (!file)
+			{
+				file = "??";
+			}
+			if (!line)
+			{
+				line = "??";
+			}
+			if (!args)
+			{
+				args = NULL;
+			}
+			if (signal_name && signal_meaning && thread_id && frame &&
+			    addr && func && file && fullname)
+			{
+				if (gdbio_setup.signal_func)
+				{
+					GdbSignalInfo si;
+					si.signal_name = signal_name;
+					si.signal_meaning = signal_meaning;
+					si.addr = addr;
+					si.func = func;
+					si.file = file;
+					si.fullname = fullname;
+					si.line = line;
+					si.from = from;
+					gdbio_setup.signal_func(&si);
+				}
+				else
+				{
+					gdbio_info_func
+						("Program received signal %s (%s) at %s in function %s() at %s:%s",
+						 signal_name, signal_meaning, addr, func, file,
+						 line);
+				}
+				return TRUE;
+			}
+		}
+
+
+		if (reason_is("end-stepping-range"))
+		{
+			return do_step_func(h, reason);
+		}
+		if (reason_is("function-finished"))
+		{
+			return do_step_func(h, reason);
+		}
+		if (reason_is("location-reached"))
+		{
+			return do_step_func(h, reason);
+		}
+		if (reason_is("watchpoint-trigger"))
+		{
+			HTAB(h, wpt);
+			if (wpt)
+			{
+				watchpoint_trigger(h, wpt, reason);
+			}
+			return do_step_func(h, reason);
+		}
+		if (reason_is("access-watchpoint-trigger"))
+		{
+			HTAB(h, hw_awpt);
+			if (hw_awpt)
+			{
+				watchpoint_trigger(h, hw_awpt, reason);
+			}
+			return do_step_func(h, reason);
+		}
+		if (reason_is("read-watchpoint-trigger"))
+		{
+			HTAB(h, hw_rwpt);
+			if (hw_rwpt)
+			{
+				watchpoint_trigger(h, hw_rwpt, reason);
+			}
+			return do_step_func(h, reason);
+		}
+		if (reason_is("watchpoint-scope"))
+		{
+			HSTR(h, wpnum);
+			gdbio_info_func("Watchpoint #%s out of scope", wpnum ? wpnum : "?");
+			gdbio_send_cmd("-exec-continue\n");
+			return do_step_func(h, reason);
+		}
+
+		if (reason_is("exited-signalled"))
+		{
+			HSTR(h, signal_name);
+			HSTR(h, signal_meaning);
+			gdbio_info_func("Program exited on signal %s (%s).\n",
+					signal_name ? signal_name : "UNKNOWN",
+					signal_meaning ? signal_meaning : "Unknown signal");
+			gdbio_target_exited(signal_name);
+			return TRUE;
+		}
+		if (reason_is("exited"))
+		{
+			HSTR(h, exit_code);
+			gchar *tail = NULL;
+			gint ec = -1;
+			if (exit_code)
+			{
+				ec = strtoull(exit_code, &tail, 8);
+				if ((!tail) || (*tail))
+				{
+					ec = -1;
+				}
+			}
+			gdbio_info_func("Program exited with code %d [%s]\n", ec,
+					exit_code ? exit_code : "(unknown)");
+			gdbio_target_exited(exit_code);
+			return TRUE;
+		}
+		if (g_str_equal(reason, "exited-normally"))
+		{
+			gdbio_info_func("Program exited normally.\n");
+			gdbio_target_exited("0");
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+
+
+static void
+handle_response_line(gchar * str, gchar ** list)
+{
+	gchar *rv = str;
+	if (!rv)
+	{
+		return;
+	}
+	switch (rv[0])
+	{
+		case '~':
+		case '@':
+		case '&':
+			{
+				rv++;
+				if (rv[0] == '"')
+				{
+					gint len = strlen(rv);
+					memmove(rv, rv + 1, len);
+					if (rv[len - 2] == '"')
+					{
+						rv[len - 2] = '\0';
+					}
+				}
+				rv = g_strcompress(rv);
+				gdbio_info_func(rv);
+				g_free(rv);
+				break;
+			}
+		case '^':
+		case '*':
+			{
+				gchar *comma = strchr(rv, ',');
+				if (comma)
+				{
+					GHashTable *h = gdblx_parse_results(comma + 1);
+					*comma = '\0';
+					if (g_str_equal(rv, "*stopped"))
+					{
+						gdbio_do_status(GdbStopped);
+					}
+					if (!handle_results_hash(h, rv, list))
+					{
+						gdblx_dump_table(h);
+					}
+					g_hash_table_destroy(h);
+				}
+				else
+				{
+					if (g_str_equal(rv, "^running"))
+					{
+						if (starting)
+						{
+							starting = FALSE;
+						}
+						else
+						{
+							gdbio_do_status(GdbRunning);
+						}
+						gdbio_set_running(TRUE);
+					}
+				}
+				break;
+			}
+		default:
+			{
+				break;
+			}
+	}
+}
+
+
+
+
+#define prompt "\n(gdb) \n"
+#define prlen 8
+
+
+#define starts_with_token(resp) \
+  ( IsDigit(resp[0]) && IsDigit(resp[1]) && \
+    IsDigit(resp[2]) && IsDigit(resp[3]) && \
+    IsDigit(resp[4]) && IsDigit(resp[5]) && \
+    strchr("^*=+", resp[6]) )
+
+
+void
+gdbio_consume_response(GString * recv_buf)
+{
+	gchar *eos = NULL;
+	do
+	{
+		if (recv_buf->len)
+		{
+			eos = strstr(recv_buf->str, prompt);
+		}
+		else
+		{
+			eos = NULL;
+		}
+		if (eos)
+		{
+			gint seq = -1;
+			gchar seqbuf[SEQ_LEN + 2];
+			ResponseHandler handler = NULL;
+			gchar **lines;
+			gint len;
+			*eos = '\0';
+			lines = g_strsplit(recv_buf->str, "\n", 0);
+			*eos = '\n';
+			len = g_strv_length(lines);
+			g_string_erase(recv_buf, 0, (eos - recv_buf->str) + 8);
+			if (len)
+			{
+				gchar *resp = lines[len - 1];
+				if (starts_with_token(resp))
+				{
+					strncpy(seqbuf, resp, SEQ_LEN);
+					seqbuf[SEQ_LEN] = '\0';
+					seq = gdbio_atoi(seqbuf);
+					if (seq >= 0)
+					{
+						handler = gdbio_seq_lookup(seq);
+						if (handler)
+						{
+							memmove(resp, resp + SEQ_LEN,
+								strlen(resp + SEQ_LEN) + 1);
+							g_strstrip(resp);
+							handler(seq, lines, resp);
+							g_strfreev(lines);
+							do_loop();
+							continue;
+						}
+						else
+						{
+							g_printerr
+								("***Error: Could not find handler for token #%s\n",
+								 seqbuf);
+						}
+					}
+				}
+			}
+			if (lines)
+			{
+				handle_response_lines(lines);
+				g_strfreev(lines);
+			}
+		}
+		do_loop();
+	}
+	while (eos);
+}
+
+
+
+
+
+void
+gdbio_continue()
+{
+	gdbio_send_cmd("-exec-continue\n");
+}
+
+
+
+
+void
+gdbio_return()
+{
+	gdbio_send_seq_cmd(return_function, "-exec-return\n");
+}
+
+
+void
+gdbio_finish()
+{
+	gdbio_send_seq_cmd(finish_function, "-exec-finish\n");
+}

Added: trunk/geanydebug/src/gdb-io-run.c
===================================================================
--- trunk/geanydebug/src/gdb-io-run.c	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io-run.c	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,778 @@
+
+/*
+ * gdb-io-run.c - Process execution and input functions for GDB wrapper library. 
+ *
+ * See the file "gdb-io.h" for license information.
+ *
+ */
+
+
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <glib.h>
+#include "gdb-io-priv.h"
+
+
+extern gint g_unlink(const gchar * filename);
+
+
+GdbIoSetup gdbio_setup;
+
+
+static gchar *gdbio_args[] = { "gdb", "--interpreter=mi", "-nx", NULL };
+
+static GPid gdbio_pid = 0;
+static GPid target_pid = 0;
+static GPid xterm_pid = 0;
+
+static GSource *gdbio_src;
+static gint gdbio_in;
+static gint gdbio_out;
+static GIOChannel *gdbio_ch_in;
+static GIOChannel *gdbio_ch_out;
+static guint gdbio_id_in;
+static guint gdbio_id_out;
+
+static GString send_buf = { NULL, 0, 0 };
+static GString recv_buf = { NULL, 0, 0 };
+
+static gchar *xterm_tty_file = NULL;
+
+
+static gint sequence = SEQ_MIN;
+static gboolean is_running = FALSE;
+static gint process_token = 0;
+
+
+/*
+  Hash table to associate a "tokenized" GDB command with a function call.
+  This stores a list of key-value pairs where the unique sequence-number
+  (GDB token) is the key, and a ResponseHandler function pointer is the value.
+*/
+static GHashTable *sequencer;
+
+
+
+/* Add a handler function to the sequencer */
+gint
+gdbio_send_seq_cmd(ResponseHandler func, const gchar * fmt, ...)
+{
+	va_list args;
+	if (!gdbio_pid)
+	{
+		return 0;
+	}
+	if (sequence >= SEQ_MAX)
+	{
+		sequence = SEQ_MIN;
+	}
+	else
+	{
+		sequence++;
+	}
+	if (!sequencer)
+	{
+		sequencer = g_hash_table_new(g_direct_hash, g_direct_equal);
+	}
+	g_hash_table_insert(sequencer, GINT_TO_POINTER(sequence), func);
+	g_string_append_printf(&send_buf, "%d", sequence);
+	va_start(args, fmt);
+	g_string_append_vprintf(&send_buf, fmt, args);
+	va_end(args);
+	return sequence;
+}
+
+
+ResponseHandler
+gdbio_seq_lookup(gint seq)
+{
+	return g_hash_table_lookup(sequencer, GINT_TO_POINTER(seq));
+}
+
+
+void
+gdbio_pop_seq(gint seq)
+{
+	g_hash_table_remove(sequencer, GINT_TO_POINTER(seq));
+}
+
+static gboolean
+gerror(gchar * msg, GError ** err)
+{
+	if (*err)
+	{
+		if (msg)
+		{
+			gdbio_error_func("%s\n%s\n", msg, (*err)->message);
+		}
+		else
+		{
+			gdbio_error_func("%s\n", (*err)->message);
+		}
+		g_error_free(*err);
+		*err = NULL;
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+
+gint
+gdbio_atoi(gchar * str)
+{
+	gchar *tail = NULL;
+	gint rv = strtol(str, &tail, 10);
+	return (tail && !*tail) ? rv : -1;
+}
+
+
+void
+gdbio_error_func(gchar * fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	gchar *msg = g_strdup_vprintf(fmt, args);
+	if (gdbio_setup.error_func)
+	{
+		gdbio_setup.error_func(g_strstrip(msg));
+	}
+	else
+	{
+		g_printerr(msg);
+	}
+	g_free(msg);
+	va_end(args);
+}
+
+
+void
+gdbio_info_func(gchar * fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	gchar *msg = g_strdup_vprintf(fmt, args);
+	if (gdbio_setup.info_func)
+	{
+		gdbio_setup.info_func(g_strstrip(msg));
+	}
+	else
+	{
+		g_printerr(msg);
+	}
+	g_free(msg);
+	va_end(args);
+}
+
+
+gint
+gdbio_wait(gint ms)
+{
+	struct timespec req = { 0, 0 }, rem =
+	{
+	0, 0};
+	gint rms = ms;
+	if (ms >= 1000)
+	{
+		req.tv_sec = ms / 1000;
+		rms = ms % 1000;
+	}
+	req.tv_nsec = rms * 1000000;	/* 1 millisecond = 1,000,000 nanoseconds */
+	do
+	{
+		nanosleep(&req, &rem);
+		if ((rem.tv_sec || rem.tv_nsec))
+		{
+			memcpy(&req, &rem, sizeof(req));
+			memset(&rem, 0, sizeof(rem));
+		}
+		else
+		{
+			break;
+		}
+
+	}
+	while (1);
+	return ms;
+}
+
+
+
+void
+gdbio_send_cmd(const gchar * fmt, ...)
+{
+	va_list args;
+	if (!gdbio_pid)
+	{
+		return;
+	}
+	va_start(args, fmt);
+	g_string_append_vprintf(&send_buf, fmt, args);
+	va_end(args);
+}
+
+
+
+void
+gdbio_set_running(gboolean running)
+{
+	is_running = running;
+}
+
+
+
+static void
+kill_xterm()
+{
+	if (xterm_pid)
+	{
+		kill(xterm_pid, SIGKILL);
+		xterm_pid = 0;
+	}
+}
+
+
+
+static gchar *
+start_xterm(gchar * term_cmd)
+{
+	gchar *term_args[] = { "xterm", "-title", "Debug terminal", "-e", NULL, NULL, NULL };
+	GError *err = NULL;
+	gint i = 0;
+	gchar *tty_name = NULL;
+	const gchar *exe_name = basename(term_cmd);
+	gchar *all;
+	if (!gdbio_setup.temp_dir)
+	{
+		gdbio_error_func("tty temporary directory not specified!\n");
+		return NULL;
+	}
+	if (!g_file_test(gdbio_setup.temp_dir, G_FILE_TEST_IS_DIR))
+	{
+		gdbio_error_func("tty temporary directory not found!\n");
+		return NULL;
+	}
+	if (!xterm_tty_file)
+	{
+		xterm_tty_file = g_strdup_printf("%s/%d.tty", gdbio_setup.temp_dir, getpid());
+	}
+	if (g_file_set_contents(xterm_tty_file, "", -1, &err))
+	{
+		g_unlink(xterm_tty_file);
+	}
+	else
+	{
+		gerror("writing ttyname logfile", &err);
+		g_unlink(xterm_tty_file);
+		return FALSE;
+	}
+	if (!gdbio_setup.tty_helper)
+	{
+		gdbio_error_func("tty helper program not specified!\n");
+		return NULL;
+	}
+	if (!
+	    (g_file_test(gdbio_setup.tty_helper, G_FILE_TEST_IS_EXECUTABLE) &&
+	     g_file_test(gdbio_setup.tty_helper, G_FILE_TEST_IS_REGULAR)))
+	{
+		gdbio_error_func("tty helper program not found!\n");
+		return NULL;
+	}
+	term_args[0] = term_cmd;
+	if (g_str_equal(exe_name, "xterm") || g_str_equal(exe_name, "konsole"))
+	{
+		term_args[1] = "-T";
+	}
+	else
+	{
+		if (g_str_equal(exe_name, "gnome-terminal"))
+		{
+			term_args[1] = "--title";
+			term_args[3] = "-x";
+		}
+		else
+		{
+			if (g_str_equal(exe_name, "rxvt") || g_str_equal(exe_name, "urxvt"))
+			{
+				term_args[1] = "-title";
+			}
+			else
+			{
+				term_args[1] = "-e";
+				term_args[2] = NULL;
+			}
+		}
+	}
+	i = 0;
+	while (term_args[i])
+	{
+		i++;
+	}
+	term_args[i] = gdbio_setup.tty_helper;
+	term_args[i + 1] = xterm_tty_file;
+	all = g_strjoinv("\"  \"", term_args);
+	gdbio_info_func("\"%s\"\n", all);
+	g_free(all);
+	if (g_spawn_async(NULL, term_args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &xterm_pid, &err))
+	{
+		gchar *contents = NULL;
+		gsize len;
+		gint ms = 0;
+		do
+		{
+			if (g_file_test(xterm_tty_file, G_FILE_TEST_EXISTS))
+			{
+				if (g_file_get_contents(xterm_tty_file, &contents, &len, &err))
+				{
+					g_strstrip(contents);
+					if (strlen(contents))
+					{
+						tty_name = g_strdup(contents);
+						gdbio_info_func("Attaching to terminal %s\n",
+								tty_name);
+					}
+					break;
+				}
+				else
+				{
+					gerror("Error getting tty name:", &err);
+				}
+			}
+			ms += gdbio_wait(250);
+		}
+		while (ms <= 10000);
+		if (ms > 10000)
+		{
+			gdbio_error_func("Timeout waitng for TTY name.\n");
+			kill_xterm();
+		}
+	}
+	else
+	{
+		gerror("Error starting terminal: ", &err);
+	}
+	g_unlink(xterm_tty_file);
+	return tty_name;
+}
+
+
+
+static void
+free_buf(GString * buf)
+{
+	if (buf->str)
+	{
+		g_free(buf->str);
+		buf->str = NULL;
+		buf->len = 0;
+		buf->allocated_len = 0;
+	}
+}
+
+static void
+shutdown_channel(GIOChannel ** ch)
+{
+	if (*ch)
+	{
+		GError *err = NULL;
+		gint fd = g_io_channel_unix_get_fd(*ch);
+		g_io_channel_shutdown(*ch, TRUE, &err);
+		gerror("Shutting down channel", &err);
+		g_io_channel_unref(*ch);
+		*ch = NULL;
+		if (fd >= 0)
+		{
+			close(fd);
+		}
+	}
+}
+
+
+static void
+on_gdb_exit(GPid pid, gint status, gpointer data)
+{
+	gdbio_pid = 0;
+	gdbio_info_func("GDB exited (pid=%d)\n", pid);
+	g_spawn_close_pid(pid);
+
+
+	g_source_remove(gdbio_id_in);
+	shutdown_channel(&gdbio_ch_in);
+
+	g_source_remove(gdbio_id_out);
+	shutdown_channel(&gdbio_ch_out);
+
+	free_buf(&send_buf);
+	if (recv_buf.len)
+	{
+		gdbio_info_func("%s\n", recv_buf.str);
+	}
+	free_buf(&recv_buf);
+
+	if (target_pid)
+	{
+		kill(target_pid, SIGKILL);
+		target_pid = 0;
+	}
+	gdbio_set_running(FALSE);
+	gdblx_scanner_done();
+	gdbio_do_status(GdbDead);
+}
+
+
+
+static gboolean
+on_send_to_gdb(GIOChannel * src, GIOCondition cond, gpointer data)
+{
+	GIOStatus st;
+	GError *err = NULL;
+	gsize count;
+	if (send_buf.len)
+	{
+		while (send_buf.len)
+		{
+			st = g_io_channel_write_chars(src, send_buf.str, send_buf.len, &count,
+						      &err);
+			g_string_erase(&send_buf, 0, count);
+			if (err || (st == G_IO_STATUS_ERROR) || (st == G_IO_STATUS_EOF))
+			{
+				gerror("Error sending command", &err);
+				break;
+			}
+		}
+		st = g_io_channel_flush(src, &err);
+		gerror("Error pushing command", &err);
+	}
+	do_loop();
+	gdbio_wait(10);
+	return TRUE;
+}
+
+
+
+void
+gdbio_target_exited(gchar * reason)
+{
+	gdbio_info_func("Target process exited. (pid=%d; %s%s)\n", target_pid,
+			reason
+			&& g_ascii_isdigit(reason[0]) ? "code=" : "reason:",
+			reason ? reason : "unknown");
+	target_pid = 0;
+	kill_xterm();
+	gdbio_set_running(FALSE);
+	gdbio_do_status(GdbFinished);
+	if (process_token)
+	{
+		gdbio_pop_seq(process_token);
+		process_token = 0;
+	}
+}
+
+static GdbStatus gdbio_status = GdbDead;
+
+void
+gdbio_do_status(GdbStatus s)
+{
+	gdbio_status = s;
+	if (gdbio_setup.status_func)
+	{
+		gdbio_setup.status_func(s);
+	}
+}
+
+
+
+void
+gdbio_pause_target()
+{
+	if (target_pid)
+	{
+		kill(target_pid, SIGINT);
+	}
+}
+
+
+
+static void
+target_killed(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	gdbio_pop_seq(seq);
+	if (h)
+	{
+		g_hash_table_destroy(h);
+	}
+	if (strncmp(resp, "^done", 5) == 0)
+	{
+		gdbio_target_exited("killed by GDB");
+	}
+}
+
+
+
+void
+gdbio_kill_target(gboolean force)
+{
+	if (target_pid)
+	{
+		gchar pidstr[64];
+		GPid this_pid = target_pid;
+		gint ms = 0;
+		snprintf(pidstr, sizeof(pidstr) - 1, "/proc/%d", target_pid);
+		if (!g_file_test(pidstr, G_FILE_TEST_IS_DIR))
+		{
+			gdbio_info_func("Directory %s not found!\n", pidstr);
+			pidstr[0] = '\0';
+		}
+		if (!force)
+		{
+			gdbio_info_func("Shutting down target program.\n");
+			gdbio_send_seq_cmd(target_killed, "kill SIGKILL\n");
+			gdbio_wait(250);
+			do_loop();
+		}
+		else
+		{
+			gdbio_info_func("Killing target program.\n");
+			kill(this_pid, SIGKILL);
+		}
+		while (1)
+		{
+			do_loop();
+			if (ms >= 2000)
+			{
+				gdbio_info_func("Timeout waiting for target process.\n");
+				if (!force)
+				{
+					gdbio_info_func("Using a bigger hammer!\n");
+					gdbio_kill_target(TRUE);
+				}
+				break;
+			}
+			if (target_pid != this_pid)
+			{
+				break;
+			}
+			if ((pidstr[0]) && !g_file_test(pidstr, G_FILE_TEST_EXISTS))
+			{
+				break;
+			}
+			if (!(ms % 1000))
+				gdbio_info_func("Waiting for target process to exit.\n");
+			ms += gdbio_wait(250);
+		}
+	}
+	kill_xterm();
+}
+
+static gboolean
+have_console()
+{
+	return (gdbio_status == GdbLoaded) || (gdbio_status == GdbStopped)
+		|| (gdbio_status == GdbFinished);
+}
+
+void
+gdbio_exit()
+{
+	gdbio_kill_target(!have_console());
+	if (gdbio_pid)
+	{
+		GPid this_gdb = gdbio_pid;
+		gint ms = 0;
+		gchar pidstr[64];
+		snprintf(pidstr, sizeof(pidstr) - 1, "/proc/%d", this_gdb);
+		if (is_running)
+		{
+			if (!g_file_test(pidstr, G_FILE_TEST_IS_DIR))
+			{
+				gdbio_info_func("Directory %s not found!\n", pidstr);
+				pidstr[0] = '\0';
+			}
+			do
+			{
+				do_loop();
+				if (gdbio_pid == this_gdb)
+				{
+					gdbio_info_func("Killing GDB (pid=%d)\n", this_gdb);
+				}
+				else
+				{
+					break;
+				}
+				kill(this_gdb, SIGKILL);
+				ms += gdbio_wait(500);
+				if (pidstr[0] && !g_file_test(pidstr, G_FILE_TEST_EXISTS))
+				{
+					break;
+				}
+				if (ms > 2000)
+				{
+					gdbio_error_func("Timeout trying to kill GDB.\n");
+					break;
+				}
+			}
+			while (1);
+			free_buf(&send_buf);
+			gdbio_wait(500);
+		}
+		else
+		{
+			gdbio_info_func("Shutting down GDB\n");
+			gdbio_send_cmd("-gdb-exit\n");
+			while (1)
+			{
+				do_loop();
+				ms += gdbio_wait(250);
+				if (pidstr[0] && !g_file_test(pidstr, G_FILE_TEST_EXISTS))
+				{
+					break;
+				}
+				if (gdbio_pid == this_gdb)
+				{
+					if (!(ms % 1000))
+						gdbio_info_func("Waiting for GDB to exit.\n");
+				}
+				else
+				{
+					break;
+				}
+				if (ms > 2000)
+				{
+					gdbio_info_func("Timeout waiting for GDB to exit.\n");
+					gdbio_set_running(TRUE);
+					gdbio_exit();
+					break;
+				}
+			}
+		}
+	}
+	if (sequencer)
+	{
+		g_hash_table_destroy(sequencer);
+		sequencer = NULL;
+	}
+	g_free(xterm_tty_file);
+	xterm_tty_file = NULL;
+}
+
+
+
+void gdbio_parse_file_list(gint seq, gchar ** list, gchar * resp);
+
+static void
+load_target(const gchar * exe_name)
+{
+	gdbio_set_running(FALSE);
+	gdbio_send_cmd("-file-exec-and-symbols %s\n", exe_name);
+	gdbio_send_seq_cmd(gdbio_parse_file_list, "-file-list-exec-source-files\n");
+
+}
+
+
+
+static gboolean
+on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer data)
+{
+	gchar buf[1024];
+	GIOStatus st;
+	GError *err = NULL;
+	gsize count;
+	st = g_io_channel_read_chars(src, buf, sizeof(buf) - 1, &count, &err);
+	buf[count] = '\0';
+	g_string_append_len(&recv_buf, buf, count);
+	gerror("Error reading response", &err);
+	gdbio_consume_response(&recv_buf);
+	gdbio_wait(10);
+	return TRUE;
+}
+
+
+#define GDB_SPAWN_FLAGS \
+G_SPAWN_SEARCH_PATH | \
+G_SPAWN_DO_NOT_REAP_CHILD
+
+
+void
+gdbio_load(const gchar * exe_name)
+{
+	GError *err = NULL;
+	gdbio_exit();
+	if (g_spawn_async_with_pipes(NULL, gdbio_args, NULL,
+				     GDB_SPAWN_FLAGS, NULL,
+				     NULL, &gdbio_pid, &gdbio_in, &gdbio_out, NULL, &err))
+	{
+		gdbio_info_func("Starting gdb (pid=%d)\n", gdbio_pid);
+
+		g_child_watch_add(gdbio_pid, on_gdb_exit, NULL);
+		gdbio_src = g_child_watch_source_new(gdbio_pid);
+
+		gdbio_ch_in = g_io_channel_unix_new(gdbio_in);
+		g_io_channel_set_encoding(gdbio_ch_in, NULL, &err);
+		gerror("Error setting encoding", &err);
+		g_io_channel_set_buffered(gdbio_ch_in, FALSE);
+
+		gdbio_ch_out = g_io_channel_unix_new(gdbio_out);
+		g_io_channel_set_encoding(gdbio_ch_out, NULL, &err);
+		gerror("Error setting encoding", &err);
+		g_io_channel_set_buffered(gdbio_ch_out, FALSE);
+
+		gdbio_id_in = g_io_add_watch(gdbio_ch_in, G_IO_OUT, on_send_to_gdb, NULL);
+		gdbio_id_out = g_io_add_watch(gdbio_ch_out, G_IO_IN, on_read_from_gdb, NULL);
+
+		gdbio_send_cmd("-gdb-set width 0\n-gdb-set height 0\n");
+		if (exe_name)
+		{
+			load_target(exe_name);
+		}
+	}
+	else
+	{
+		gerror("Error starting debugger.", &err);
+	}
+}
+
+
+
+void
+gdbio_exec_target(gchar * terminal_command)
+{
+	if (terminal_command)
+	{
+		gchar *tty_name = start_xterm(terminal_command);
+		if (tty_name)
+		{
+			gdbio_send_cmd("-inferior-tty-set %s\n", tty_name);
+			g_free(tty_name);
+		}
+		else
+			return;
+	}
+	if (process_token)
+	{
+		gdbio_pop_seq(process_token);
+	}
+	gdbio_set_starting(TRUE);
+	gdbio_do_status(GdbStartup);
+	process_token = gdbio_send_seq_cmd(gdbio_target_started, "-exec-run\n");
+}
+
+
+
+void
+gdbio_set_target_pid(GPid pid)
+{
+	gdbio_info_func("Started target process. (pid=%d)\n", pid);
+	target_pid = pid;
+}
+
+
+
+GPid
+gdbio_get_target_pid()
+{
+	return target_pid;
+}

Added: trunk/geanydebug/src/gdb-io-stack.c
===================================================================
--- trunk/geanydebug/src/gdb-io-stack.c	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io-stack.c	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,198 @@
+
+/*
+ * gdb-io-stack.c - Stack information functions for GDB wrapper library. 
+ *
+ * See the file "gdb-io.h" for license information.
+ *
+ */
+
+#include <string.h>
+#include <glib.h>
+
+#include "gdb-io-priv.h"
+
+static GdbListFunc gdbio_stack_list_func = NULL;
+static GSList *frame_list = NULL;
+
+/*
+  Max number of frames to return in stack list -
+  you can increase if you want, but too large
+  value can be *very* slow!
+*/
+#define MAX_STACK_RETURN 1024
+
+
+
+static void
+free_frame_list()
+{
+	GSList *p;
+	for (p = frame_list; p; p = p->next)
+	{
+		if (p->data)
+		{
+			GdbFrameInfo *f = p->data;
+			if (f->func)
+			{
+				g_free(f->func);
+			}
+			if (f->filename)
+			{
+				g_free(f->filename);
+			}
+			if (f->args)
+			{
+				gdbio_free_var_list(f->args);
+			}
+			g_free(f);
+			p->data = NULL;
+		}
+	}
+	g_slist_free(frame_list);
+	frame_list = NULL;
+}
+
+
+
+static void
+stack_cb(gpointer data, gpointer user_data)
+{
+	GdbLxValue *v = (GdbLxValue *) data;
+	if (v && (v->type == vt_HASH))
+	{
+		GHashTable *frame = v->hash;
+		HSTR(frame, level);
+		HSTR(frame, addr);
+		HSTR(frame, func);
+		HSTR(frame, file);
+		HSTR(frame, fullname);
+		HSTR(frame, line);
+		if (!fullname)
+			fullname = file;
+		if (level && addr && func && fullname && line)
+		{
+			GdbFrameInfo *frame = g_new0(GdbFrameInfo, 1);
+			strncpy(frame->level, level, sizeof(frame->level) - 1);
+			strncpy(frame->addr, addr, sizeof(frame->addr) - 1);
+			strncpy(frame->line, line, sizeof(frame->line) - 1);
+			frame->func = g_strdup(func);
+			frame->filename = g_strdup(fullname);
+			frame_list = g_slist_append(frame_list, frame);
+		}
+	}
+}
+
+
+
+static void
+merge_stack_args_cb(gpointer data, gpointer user_data)
+{
+	GdbLxValue *v = (GdbLxValue *) data;
+	if (v && (v->type = vt_HASH))
+	{
+		GHashTable *hash = v->hash;
+		HSTR(hash, level);
+		HLST(hash, args);
+		if (level && args)
+		{
+			gchar *tail;
+			gint n = strtoull(level, &tail, 10);
+			GdbFrameInfo *frame = NULL;
+			GSList *p;
+			for (p = frame_list; p; p = p->next)
+			{
+				if (p->data)
+				{
+					GdbFrameInfo *f = p->data;
+					if (gdbio_atoi(f->level) == n)
+					{
+						frame = f;
+						break;
+					}
+				}
+			}
+			if (frame)
+			{
+				for (p = args; p; p = p->next)
+				{
+					v = p->data;
+					if (v && (v->type = vt_HASH))
+					{
+						HSTR(v->hash, name);
+						HSTR(v->hash, value);
+						if (name && value)
+						{
+							GdbVar *arg = g_new0(GdbVar, 1);
+							arg->name = g_strdup(name);
+							arg->value = g_strdup(value);
+							frame->args =
+								g_slist_append(frame->args, arg);
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+
+
+static void
+parse_stack_args(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HLST(h, stack_args);
+	gdbio_pop_seq(seq);
+	if (stack_args)
+	{
+		if (frame_list)
+		{
+			g_slist_foreach(stack_args, merge_stack_args_cb, NULL);
+			gdbio_stack_list_func(frame_list);
+			free_frame_list();
+		}
+	}
+	if (h)
+		g_hash_table_destroy(h);
+}
+
+
+
+static void
+parse_stack_list(gint seq, gchar ** list, gchar * resp)
+{
+	GHashTable *h = gdbio_get_results(resp, list);
+	HLST(h, stack);
+	gdbio_pop_seq(seq);
+	if (stack)
+	{
+		g_slist_foreach(stack, stack_cb, h);
+		if (frame_list)
+		{
+			gint len = g_slist_length(frame_list);
+			if (len >= MAX_STACK_RETURN)
+			{
+				gdbio_error_func
+					("Stack too deep to display!\n(Showing only %d frames)",
+					 len);
+			}
+			gdbio_send_seq_cmd(parse_stack_args, "-stack-list-arguments 1 0 %d\n",
+					   len - 1);
+		}
+	}
+	if (h)
+		g_hash_table_destroy(h);
+}
+
+
+
+void
+gdbio_show_stack(GdbListFunc func)
+{
+	gdbio_stack_list_func = func;
+	if (func)
+	{
+		gdbio_send_seq_cmd(parse_stack_list, "-stack-list-frames 0 %d\n",
+				   MAX_STACK_RETURN - 1);
+	}
+}

Added: trunk/geanydebug/src/gdb-io.h
===================================================================
--- trunk/geanydebug/src/gdb-io.h	                        (rev 0)
+++ trunk/geanydebug/src/gdb-io.h	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,231 @@
+/*
+ * gdb-io.h - A GLib-based library wrapper for the GNU debugger.
+ * Copyright 2008 Jeff Pohlmeyer <yetanothergeek(at)gmail(dot)com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+extern ssize_t getline(char **lineptr, size_t * n, FILE * stream);
+extern const gchar *basename(const gchar * path);
+
+gint gdbio_atoi(gchar * str);
+gint gdbio_wait(gint ms);
+
+
+typedef enum
+{
+	GdbDead,
+	GdbLoaded,
+	GdbStartup,
+	GdbRunning,
+	GdbStopped,
+	GdbFinished
+} GdbStatus;
+
+
+typedef struct
+{
+	gchar *type;
+	gchar *name;
+	gchar *value;
+	gchar *numchild;
+} GdbVar;
+
+
+typedef struct
+{
+	gchar level[12];
+	gchar addr[12];
+	gchar line[12];
+	gchar *func;
+	gchar *filename;
+	GSList *args;
+} GdbFrameInfo;
+
+
+typedef struct
+{
+	gchar *signal_name;
+	gchar *signal_meaning;
+	gchar *addr;
+	gchar *func;
+	gchar *file;
+	gchar *fullname;
+	gchar *line;
+	gchar *from;
+} GdbSignalInfo;
+
+
+typedef struct
+{
+	gchar *addr;
+	gchar *disp;
+	gchar *enabled;
+	gchar *file;
+	gchar *fullname;
+	gchar *func;
+	gchar *line;
+	gchar *number;
+	gchar *times;
+	gchar *type;
+	gchar *what;
+	gchar *cond;
+	gchar *ignore;
+} GdbBreakPointInfo;
+
+
+typedef struct
+{
+	gchar *cwd;
+	gchar *path;
+	gchar *args;
+	gchar *dirs;
+} GdbEnvironInfo;
+
+
+typedef void (*GdbMsgFunc) (const gchar * msg);
+typedef void (*GdbListFunc) (const GSList * list);
+typedef void (*GdbFrameFunc) (const GdbFrameInfo * frame, const GSList * locals);
+typedef void (*GdbSignalFunc) (const GdbSignalInfo * si);
+typedef void (*GdbStatusFunc) (GdbStatus status);
+typedef void (*GdbStepFunc) (const gchar * filename, const gchar * line, const gchar * reason);
+typedef void (*GdbObjectFunc) (const GdbVar * obj, const GSList * list);
+typedef void (*GdbEnvironFunc) (const GdbEnvironInfo * env);
+
+
+
+/* Load a program into the debugger */
+void gdbio_load(const gchar * exe_name);
+
+/* Terminate the debugger ( and the target program, if running ) */
+void gdbio_exit();
+
+/* Resume execution after a breakpoint or SIGINT, etc... */
+void gdbio_continue();
+
+/* Complete the current function */
+void gdbio_finish();
+
+/* Return immediately from the current function */
+void gdbio_return();
+
+/*
+  Execute the previously loaded program in the debugger.
+  If the terminal_command argument is non-null, it will
+  be started first, and the target program will be run
+  in the resulting console.
+*/
+void gdbio_exec_target(gchar * terminal_command);
+
+
+/* Send SIGINT to target */
+void gdbio_pause_target();
+
+
+/* Send SIGKILL to target */
+void gdbio_kill_target();
+
+
+/* Send a command to GDB */
+void gdbio_send_cmd(const gchar * fmt, ...);
+
+
+/*
+  Pass a GSList of GdbBreakPointInfo pointers to the func callback
+  Showing the current list of breakpoints and watchpoints
+*/
+void gdbio_show_breaks(GdbListFunc func);
+
+
+/*
+  These 3 functions pass a GSList of GdbBreakPointInfo pointers to
+  the func callback showing the current list of breakpoints and
+  watchpoints after the requested change has been completed.
+*/
+void gdbio_add_watch(GdbListFunc func, const gchar * option, const gchar * varname);
+void gdbio_add_break(GdbListFunc func, const gchar * filename, const gchar * locn);
+void gdbio_delete_break(GdbListFunc func, const gchar * number);
+
+
+void gdbio_enable_break(const gchar * number, gboolean enabled);
+void gdbio_ignore_break(const gchar * number, const gchar * times);
+void gdbio_break_cond(const gchar * number, const gchar * expr);
+
+
+
+/*
+  Pass a GdbEnvironInfo pointer to the callback to show some
+  information about current GDB settings.
+*/
+void gdbio_get_env(GdbEnvironFunc func);
+
+
+/*
+  Pass a GSList of GdbFrameInfo pointers to the func callback
+  representing a backtrace of current call stack.
+*/
+void gdbio_show_stack(GdbListFunc func);
+
+
+/*
+  Passes a GdbFrameInfo pointer and a GSList of GdbVar pointers to func
+  representing the state of the local variables at the specified level.
+*/
+void gdbio_show_locals(GdbFrameFunc func, gchar * level);
+
+
+/*
+  Passes GdbVar pointer containing information about the variable to
+  the callback along with a GSList of GdbVar pointers containing
+  information about each array element or struct field.
+*/
+void gdbio_show_object(GdbObjectFunc func, const gchar * varname);
+
+
+
+/*
+  The fields of the gdbio_setup struct should be initialized by the
+  client application before loading the first target program.
+
+  The tty_helper field must point to the full path and filename
+  of the included "ttyhelper" program (see ttyhelper.c)
+
+  The temp_dir must point to a readable and writeable directory.
+
+  The client is also responsible for allocating/freeing the
+  string fields.
+*/
+
+typedef struct _GdbIoSetup
+{
+	GdbMsgFunc info_func;
+	GdbMsgFunc error_func;
+	GdbSignalFunc signal_func;
+	GdbStatusFunc status_func;
+	GdbStepFunc step_func;
+	gchar *tty_helper;
+	gchar *temp_dir;
+} GdbIoSetup;
+
+extern GdbIoSetup gdbio_setup;

Added: trunk/geanydebug/src/gdb-lex.c
===================================================================
--- trunk/geanydebug/src/gdb-lex.c	                        (rev 0)
+++ trunk/geanydebug/src/gdb-lex.c	2008-09-07 20:36:07 UTC (rev 169)
@@ -0,0 +1,337 @@
+
+/*
+ * gdb-lex.c - A GLib-based parser for GNU debugger machine interface output.
+ *
+ * See the file "gdb-lex.h" for license information.
+ *
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "gdb-lex.h"
+
+
+static void
+free_value(GdbLxValue * v)
+{
+	if (v)
+	{
+		switch (v->type)
+		{
+			case vt_STRING:
+				{
+					g_free(v->string);
+					break;
+				}
+			case vt_HASH:
+				{
+					g_hash_table_destroy(v->hash);
+					break;
+				}
+			case vt_LIST:
+				{
+					GSList *p;
+					for (p = v->list; p; p = p->next)
+					{
+						free_value(p->data);
+					}
+					g_slist_free(v->list);
+					break;
+				}
+		}
+	}
+}
+
+
+static GdbLxValue *
+new_value(GdbLxValueType type, gpointer data)
+{
+	GdbLxValue *v = g_new0(GdbLxValue, 1);
+	v->type = type;
+	v->data = data;
+	return v;
+}
+
+
+static void
+scan_error(GScanner * scanner, gchar * message, gboolean error)
+{
+	g_printerr("\n%s\n", message);
+}
+
+
+
+
+#define ID_NTH G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-"
+static GScanner *
+init_scanner()
+{
+	GScanner *scanner = g_scanner_new(NULL);
+	scanner->msg_handler = scan_error;
+	scanner->config->cset_identifier_nth = ID_NTH;
+	return scanner;
+}
+
+
+#define new_hash() g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)free_value)
+#define curr ((GdbLxValue*)(g_queue_peek_head(queue)))
+
+
+
+static void
+add_node(GScanner * scanner, gchar ** key, GdbLxValueType type, gpointer data, GQueue * queue)
+{
+	GdbLxValue *v = new_value(type, data);
+	switch (curr->type)
+	{
+		case vt_STRING:
+			{
+				g_scanner_error(scanner, "***** queue head is a string\n");
+				break;
+			}
+		case vt_HASH:
+			{
+				if (*key)
+				{
+					g_hash_table_insert(curr->hash, *key, v);
+				}
+				else
+				{
+					g_scanner_error(scanner, "***** no key for hash\n");
+				}
+				break;
+			}
+		case vt_LIST:
+			{
+				curr->list = g_slist_append(curr->list, v);
+				break;
+			}
+	}
+	*key = NULL;
+	if (type != vt_STRING)
+	{
+		g_queue_push_head(queue, v);
+	}
+}
+
+
+static GScanner *scanner = NULL;
+
+GHashTable *
+gdblx_parse_results(gchar * results)
+{
+	gchar *key = NULL;
+	gboolean equals = FALSE;
+	GHashTable *rv = new_hash();
+	GdbLxValue *top = new_value(vt_HASH, rv);
+	GQueue *queue = g_queue_new();
+	g_queue_push_head(queue, top);
+	GTokenType tt;
+	if (!scanner)
+	{
+		scanner = init_scanner();
+	}
+	g_scanner_input_text(scanner, results, strlen(results));
+	do
+	{
+		tt = g_scanner_get_next_token(scanner);
+		switch (tt)
+		{
+			case G_TOKEN_LEFT_CURLY:
+				{
+					add_node(scanner, &key, vt_HASH, new_hash(), queue);
+					break;
+				}
+			case G_TOKEN_RIGHT_CURLY:
+				{
+					g_queue_pop_head(queue);
+					break;
+				}
+			case G_TOKEN_LEFT_BRACE:
+				{
+					add_node(scanner, &key, vt_LIST, NULL, queue);
+					break;
+				}
+			case G_TOKEN_RIGHT_BRACE:
+				{
+					g_queue_pop_head(queue);
+					break;
+				}
+			case G_TOKEN_STRING:
+				{
+					add_node(scanner, &key, vt_STRING,
+						 g_strdup(scanner->value.v_string), queue);
+					break;
+				}
+
+			case G_TOKEN_IDENTIFIER:
+				{
+					if (g_scanner_peek_next_token(scanner) ==
+					    G_TOKEN_EQUAL_SIGN)
+					{
+						gchar *p;
+						if (key)
+						{
+							g_scanner_error(scanner,
+									"multiple keys: found %s and %s\n",
+									key,
+									scanner->value.
+									v_identifier);
+							g_free(key);
+						}
+						key = g_strdup(scanner->value.v_identifier);
+						for (p = key; *p; p++)
+						{
+							if (*p == '-')
+							{
+								*p = '_';
+							}
+						}
+					}
+					break;
+				}
+			default:
+				{
+				}
+				equals = (tt == G_TOKEN_EQUAL_SIGN);
+		}
+	}
+	while ((tt != G_TOKEN_EOF) && (tt != G_TOKEN_ERROR));
+	g_queue_free(queue);
+	return rv;
+}
+
+
+void
+gdblx_scanner_done()
+{
+	if (scanner)
+	{
+		g_scanner_destroy(scanner);
+		scanner = NULL;
+	}
+}
+
+
+/* don't print the newline until after the rval of the equal sign is printed. */
+static gboolean dump_value_rval_pending = FALSE;
+
+#define indent(s) if (dump_value_rval_pending) \
+g_printerr("%s\n", s); \
+else g_printerr("%*c%s\n", depth,  ' ', s); \
+  dump_value_rval_pending = FALSE;
+
+
+static void dump_rec(GHashTable * h, gint depth);
+
+
+static void dump_list_cb(gpointer data, gpointer user_data);
+
+static void
+dump_value(GdbLxValue * v, gint depth)
+{
+	switch (v->type)
+	{
+		case vt_STRING:
+			{
+				indent(v->string);
+				break;
+			}
+		case vt_HASH:
+			{
+				indent("{");
+				dump_rec(v->hash, depth);
+				indent("}");
+				break;
+			}
+		case vt_LIST:
+			{
+				indent("[");
+				g_slist_foreach(v->list, dump_list_cb, GINT_TO_POINTER(depth) + 1);
+				indent("]");
+				break;
+			}
+	}
+}
+
+
+
+static void
+dump_list_cb(gpointer data, gpointer user_data)
+{
+	dump_value(data, GPOINTER_TO_INT(user_data));
+}
+
+
+
+static void
+dump_rec_cb(gpointer key, gpointer value, gpointer user_data)
+{
+	g_printerr("%*c%s=", GPOINTER_TO_INT(user_data), ' ', (gchar *) key);
+	dump_value_rval_pending = TRUE;
+	dump_value(value, GPOINTER_TO_INT(user_data));
+}
+
+
+
+static void
+dump_rec(GHashTable * h, gint depth)
+{
+	if (h)
+	{
+		g_hash_table_foreach(h, dump_rec_cb, GINT_TO_POINTER(depth) + 1);
+	}
+	else
+	{

@@ Diff output truncated at 100000 characters. @@

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Plugins-Commits mailing list