<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.comp.lib.agar.scm">
    <title>gmane.comp.lib.agar.scm</title>
    <link>http://blog.gmane.org/gmane.comp.lib.agar.scm</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1417"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1416"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1415"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1414"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1413"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1412"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1411"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1410"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1409"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1408"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1407"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1406"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1405"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1404"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1403"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1402"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1401"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1400"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1399"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.agar.scm/1398"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1417">
    <title>Agar: r9104 - trunk/gui</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1417</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-05-18 22:31:27 -0400 (Fri, 18 May 2012)
New Revision: 9104

Modified:
   trunk/gui/AG_Table.3
Log:
mention that %[W] widgets are freed when cells are removed



Modified: trunk/gui/AG_Table.3
===================================================================
--- trunk/gui/AG_Table.32012-05-19 02:30:25 UTC (rev 9103)
+++ trunk/gui/AG_Table.32012-05-19 02:31:27 UTC (rev 9104)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -490,6 +490,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 (e.g., the
 .Fa parent
 argument of standard constructor routines should be NULL).
+Embedded widgets are automatically freed when cells are deleted.
 .El
 .Pp
 The functions
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-05-19T02:31:27</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1416">
    <title>Agar: r9103 - trunk/gui</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1416</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-05-18 22:30:25 -0400 (Fri, 18 May 2012)
New Revision: 9103

Modified:
   trunk/gui/AG_Surface.3
Log:
document AG_ReadSurfaceFrom*() routines



Modified: trunk/gui/AG_Surface.3
===================================================================
--- trunk/gui/AG_Surface.32012-04-06 07:32:59 UTC (rev 9102)
+++ trunk/gui/AG_Surface.32012-05-19 02:30:25 UTC (rev 9103)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,4 +1,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-.\" Copyright (c) 2006-2011 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+.\" Copyright (c) 2006-2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -95,6 +95,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Ft "AG_Surface *"
 .Fn AG_SurfaceFromBMP "const char *path"
 .Pp
+.Ft "AG_Surface *"
+.Fn AG_ReadSurfaceFromPNG "AG_DataSource *ds"
+.Pp
+.Ft "AG_Surface *"
+.Fn AG_ReadSurfaceFromJPEG "AG_DataSource *ds"
+.Pp
+.Ft "AG_Surface *"
+.Fn AG_ReadSurfaceFromBMP "AG_DataSource *ds"
+.Pp
 .Bd -literal
 /* Requires Agar compiled --with-sdl */
 .Ed
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -244,6 +253,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Fn AG_SurfaceFromJPEG
 will return an error unless Agar was compiled with support for libpng
 and libjpeg, respectively.
+The
+.Fn AG_ReadSurfaceFromPNG ,
+.Fn AG_ReadSurfaceFromJPEG
+and
+.Fn AG_ReadSurfaceFromBMP
+variants can be used to load an image file from an arbitrary data
+source (see
+.Xr AG_DataSource 3 ) .
 .Pp
 The
 .Fn AG_SurfaceFromSDL
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-05-19T02:30:26</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1415">
    <title>Agar: r9102 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1415</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-06 03:32:59 -0400 (Fri, 06 Apr 2012)
New Revision: 9102

Modified:
   trunk/core/asprintf.c
Log:
use TryVasprintf()



Modified: trunk/core/asprintf.c
===================================================================
--- trunk/core/asprintf.c2012-04-06 05:21:53 UTC (rev 9101)
+++ trunk/core/asprintf.c2012-04-06 07:32:59 UTC (rev 9102)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -113,7 +113,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 int rv;
 
 va_start(ap, fmt);
-rv = AG_Vasprintf(ret, fmt, ap);
+rv = AG_TryVasprintf(ret, fmt, ap);
 va_end(ap);
 
 if (rv == -1) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -130,7 +130,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 int rv;
 
 va_start(ap, fmt);
-rv = AG_Vasprintf(ret, fmt, ap);
+rv = AG_TryVasprintf(ret, fmt, ap);
 va_end(ap);
 
 if (rv == -1)
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T07:32:59</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1414">
    <title>Agar: r9101 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1414</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-06 01:21:53 -0400 (Fri, 06 Apr 2012)
New Revision: 9101

Modified:
   trunk/core/asprintf.c
Log:
fix typo in va_start()



Modified: trunk/core/asprintf.c
===================================================================
--- trunk/core/asprintf.c2012-04-06 05:16:29 UTC (rev 9100)
+++ trunk/core/asprintf.c2012-04-06 05:21:53 UTC (rev 9101)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -112,7 +112,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 va_list ap;
 int rv;
 
-ap = va_start(ap, fmt);
+va_start(ap, fmt);
 rv = AG_Vasprintf(ret, fmt, ap);
 va_end(ap);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -129,7 +129,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 va_list ap;
 int rv;
 
-ap = va_start(ap, fmt);
+va_start(ap, fmt);
 rv = AG_Vasprintf(ret, fmt, ap);
 va_end(ap);
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T05:21:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1413">
    <title>Agar: r9100 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1413</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-06 01:16:29 -0400 (Fri, 06 Apr 2012)
New Revision: 9100

Modified:
   trunk/core/db_bdb.c
Log:
fix typo in class description



Modified: trunk/core/db_bdb.c
===================================================================
--- trunk/core/db_bdb.c2012-04-06 05:13:39 UTC (rev 9099)
+++ trunk/core/db_bdb.c2012-04-06 05:16:29 UTC (rev 9100)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -267,7 +267,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 };
 AG_DbClass agDbBtreeClass = {
 {
-"Agar(Db:DbHash)",
+"Agar(Db:DbBtree)",
 sizeof(AG_DbHashBT),
 { 0,0 },
 Init,
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T05:16:29</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1412">
    <title>Agar: r9099 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1412</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-06 01:13:39 -0400 (Fri, 06 Apr 2012)
New Revision: 9099

Modified:
   trunk/core/asprintf.c
   trunk/core/snprintf.c
Log:
compile correctly in !HAVE_FOO case



Modified: trunk/core/asprintf.c
===================================================================
--- trunk/core/asprintf.c2012-04-06 05:13:09 UTC (rev 9098)
+++ trunk/core/asprintf.c2012-04-06 05:13:39 UTC (rev 9099)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -88,7 +88,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 va_end(ap);
 if (size &amp;lt;= buflen) {
 *ret = buf;
-return (size);
+return;
 }
 if ((bufNew = TryRealloc(buf, size+1)) == NULL) {
 Free(buf);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -99,7 +99,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 size = vsprintf(buf, fmt, ap);
 va_end(ap);
 *ret = buf;
-return (size);
+return;
 fail:
 AG_FatalError("asprintf: Out of memory");
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -112,7 +112,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 va_list ap;
 int rv;
 
-ap = va_start(fmt);
+ap = va_start(ap, fmt);
 rv = AG_Vasprintf(ret, fmt, ap);
 va_end(ap);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -129,7 +129,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 va_list ap;
 int rv;
 
-ap = va_start(fmt);
+ap = va_start(ap, fmt);
 rv = AG_Vasprintf(ret, fmt, ap);
 va_end(ap);
 

Modified: trunk/core/snprintf.c
===================================================================
--- trunk/core/snprintf.c2012-04-06 05:13:09 UTC (rev 9098)
+++ trunk/core/snprintf.c2012-04-06 05:13:39 UTC (rev 9099)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -64,7 +64,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;stdarg.h&amp;gt;
 #include &amp;lt;string.h&amp;gt;
 
-#include "snprintf.h"
+#include "core.h"
 
 static void dopr(char *, size_t, const char *, va_list);
 static void fmtstr(char *, size_t *, size_t, char *, int, int, int);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -473,7 +473,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 convert[place] = 0;
 
 zpadlen = max - place;
-spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+spadlen = min - AG_MAX(max, place) - (signvalue ? 1 : 0);
 if (zpadlen &amp;lt; 0)
 zpadlen = 0;
 if (spadlen &amp;lt; 0)
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T05:13:39</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1411">
    <title>Agar: r9098 - trunk</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1411</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-06 01:13:09 -0400 (Fri, 06 Apr 2012)
New Revision: 9098

Modified:
   trunk/configure
   trunk/configure.in
Log:
update CONFIG_SCRIPT()



Modified: trunk/configure
===================================================================
--- trunk/configure2012-04-06 02:14:53 UTC (rev 9097)
+++ trunk/configure2012-04-06 05:13:09 UTC (rev 9098)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -9590,7 +9590,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "mdefs[\"CXXFLAGS\"] = \"$CXXFLAGS\"" &amp;gt;&amp;gt;configure.lua
 config_script_out="agar-config"
 config_script_cflags="-I${INCLDIR} ${SDL_CFLAGS} ${FREETYPE_CFLAGS} ${OPENGL_CFLAGS} ${X11_CFLAGS} ${GLX_CFLAGS} ${XINERAMA_CFLAGS} ${MATH_CFLAGS} ${PNG_CFLAGS} ${PTHREADS_CFLAGS} ${DB4_CFLAGS} ${MYSQL_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}"
-config_script_libs="-L${LIBDIR} -lag_gui -lag_core ${SDL_LIBS} ${FREETYPE_LIBS} ${OPENGL_LIBS} ${X11_LIBS} ${XINERAMA_LIBS} ${MATH_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}"
+config_script_libs="-L${LIBDIR} -lag_gui -lag_core ${SDL_LIBS} ${FREETYPE_LIBS} ${OPENGL_LIBS} ${X11_LIBS} ${XINERAMA_LIBS} ${MATH_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${MYSQL_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}"
 # Avoid breakage with existing trees compiled before BSDBuild 2.8.
 if [ -d "$config_script_out" ]; then
 echo "rm -fR $config_script_out"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -9670,7 +9670,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 done
 EOT
 config_script_out="agar-core-config"
-config_script_cflags="-I${INCLDIR} ${SDL_CFLAGS} ${MATH_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}"
+config_script_cflags="-I${INCLDIR} ${MATH_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}"
 config_script_libs="-L${LIBDIR} -lag_core ${MATH_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${MYSQL_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}"
 # Avoid breakage with existing trees compiled before BSDBuild 2.8.
 if [ -d "$config_script_out" ]; then

Modified: trunk/configure.in
===================================================================
--- trunk/configure.in2012-04-06 02:14:53 UTC (rev 9097)
+++ trunk/configure.in2012-04-06 05:13:09 UTC (rev 9098)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -681,8 +681,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 C_INCDIR_CONFIG($BLD/include/agar/config)
 
 # Generate the "foo-config" scripts.
-CONFIG_SCRIPT(agar-config, "-I${INCLDIR} ${SDL_CFLAGS} ${FREETYPE_CFLAGS} ${OPENGL_CFLAGS} ${X11_CFLAGS} ${GLX_CFLAGS} ${XINERAMA_CFLAGS} ${MATH_CFLAGS} ${PNG_CFLAGS} ${PTHREADS_CFLAGS} ${DB4_CFLAGS} ${MYSQL_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_gui -lag_core ${SDL_LIBS} ${FREETYPE_LIBS} ${OPENGL_LIBS} ${X11_LIBS} ${XINERAMA_LIBS} ${MATH_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
-CONFIG_SCRIPT(agar-core-config, "-I${INCLDIR} ${SDL_CFLAGS} ${MATH_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_core ${MATH_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${MYSQL_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
+CONFIG_SCRIPT(agar-config, "-I${INCLDIR} ${SDL_CFLAGS} ${FREETYPE_CFLAGS} ${OPENGL_CFLAGS} ${X11_CFLAGS} ${GLX_CFLAGS} ${XINERAMA_CFLAGS} ${MATH_CFLAGS} ${PNG_CFLAGS} ${PTHREADS_CFLAGS} ${DB4_CFLAGS} ${MYSQL_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_gui -lag_core ${SDL_LIBS} ${FREETYPE_LIBS} ${OPENGL_LIBS} ${X11_LIBS} ${XINERAMA_LIBS} ${MATH_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${MYSQL_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
+CONFIG_SCRIPT(agar-core-config, "-I${INCLDIR} ${MATH_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_core ${MATH_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${MYSQL_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
 CONFIG_SCRIPT(agar-dev-config, "-I${INCLDIR} ${GETTEXT_CFLAGS}", "-L${LIBDIR} -lag_dev ${GETTEXT_LIBS}")
 CONFIG_SCRIPT(agar-math-config, "-I${INCLDIR} ${MATH_CFLAGS} ${GETTEXT_CFLAGS}", "-L${LIBDIR} -lag_math ${MATH_LIBS} ${GETTEXT_LIBS}")
 CONFIG_SCRIPT(agar-rg-config, "-I${INCLDIR} ${GETTEXT_CFLAGS}", "-L${LIBDIR} -lag_rg ${GETTEXT_LIBS}")
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T05:13:10</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1410">
    <title>Agar: r9097 - trunk</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1410</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-05 22:14:53 -0400 (Thu, 05 Apr 2012)
New Revision: 9097

Modified:
   trunk/configure
   trunk/configure.in
Log:
add AG_Db options



Modified: trunk/configure
===================================================================
--- trunk/configure2012-04-06 02:13:13 UTC (rev 9096)
+++ trunk/configure2012-04-06 02:14:53 UTC (rev 9097)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -379,7 +379,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "    --with-manlinks           Add manual entries for every function [no]"
 echo "    --with-manpages           Generate Unix manual pages [yes]"
 echo ""
-echo "Options specific to Agar:"
+echo "Options global to Agar:"
 echo "    --enable-&amp;lt;library&amp;gt;        Build libraries (gui|vg|rg|math|dev) [all]"
 echo "    --enable-debug            General debugging [no]"
 echo "    --enable-legacy           Deprecated interfaces [yes]"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -387,10 +387,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "    --enable-objdebug         Object system debugging [no]"
 echo "    --enable-threads          Thread safety [check]"
 echo "    --enable-warnings         Suggested compiler warnings [no]"
-echo "    --with-db4[=PREFIX]       AG_Db: Berkeley DB backend [check]"
-echo "    --with-pthreads[=PREFIX]  Specify libpthreads location [check]"
+echo "    --with-pthreads[=PREFIX]  POSIX Threads support [check]"
 echo ""
-echo "Options specific to ag_gui library:"
+echo "Options specific to AG_Db(3) interface:"
+echo "    --with-db4[=PREFIX]       Enable Berkeley DB backend [check]"
+echo "    --with-mysql[=PREFIX]     Enable MySQL backend [check]"
+echo ""
+echo "Options specific to GUI library:"
 echo "    --with-freetype[=PREFIX]  Enable FreeType support [check]"
 echo "    --with-gl[=PREFIX]        OpenGL rendering support [check]"
 echo "    --with-glx[=PREFIX]       GL rendering via GLX [check]"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -401,13 +404,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "    --with-xinerama[=PREFIX]  Xinerama extension support [check]"
 echo "    --with-wgl                GL rendering via WGL [check]"
 echo ""
-echo "Options specific to ag_math library:"
+echo "Options specific to Math library:"
 echo "    --with-altivec            AltiVec optimizations [check]"
 echo "    --with-sse                SSE[123] optimizations [no]"
 echo "    --with-&amp;lt;mode&amp;gt;-fp          Precision (single|double|quad) [double]"
 echo "    --with-&amp;lt;opt&amp;gt;-inline       Inline ops (sse2|sse3|altivec) [no]"
 echo ""
-echo "Options specific to ag_au library:"
+echo "Options specific to Audio library:"
 echo "    --enable-audio            Build audio interface library [no]"
 echo "    --with-sndfile[=PREFIX]   Use sndfile library [check]"
 echo "    --with-portaudio[=PREFIX] Use portaudio library [check]"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2516,6 +2519,63 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo $MK_COMPILE_STATUS &amp;gt; ${cache}/ctest-status-HAVE_STRSEP
 fi
 rm -f conftest.c $testdir/conftest$EXECSUFFIX
+$ECHO_N "checking for an asprintf() function..."
+$ECHO_N "checking for an asprintf() function..." &amp;gt;&amp;gt; config.log
+MK_CACHED="No"
+MK_COMPILE_STATUS="OK"
+if [ "${cache}" != "" ]; then
+if [ -e "${cache}/ctest-HAVE_ASPRINTF" ]; then
+HAVE_ASPRINTF=`cat ${cache}/ctest-HAVE_ASPRINTF`
+MK_COMPILE_STATUS=`cat ${cache}/ctest-status-HAVE_ASPRINTF`
+MK_CACHED="Yes"
+fi
+fi
+if [ "${MK_CACHED}" = "No" ]; then
+cat &amp;lt;&amp;lt; EOT &amp;gt; conftest.c
+#include &amp;lt;stdio.h&amp;gt;
+
+int
+main(int argc, char *argv[])
+{
+char *buf;
+if (asprintf(&amp;amp;buf, "foo %s", "bar") == 0) {
+    return (0);
+}
+return (1);
+}
+
+EOT
+echo "$CC $CFLAGS $TEST_CFLAGS -D_GNU_SOURCE -o $testdir/conftest conftest.c" &amp;gt;&amp;gt;config.log
+$CC $CFLAGS $TEST_CFLAGS -D_GNU_SOURCE -o $testdir/conftest conftest.c 2&amp;gt;&amp;gt;config.log
+if [ $? != 0 ]; then
+echo "-&amp;gt; failed ($?)" &amp;gt;&amp;gt; config.log
+MK_COMPILE_STATUS="FAIL($?)"
+fi
+fi
+if [ "${MK_COMPILE_STATUS}" = "OK" ]; then
+echo "yes"
+echo "yes" &amp;gt;&amp;gt; config.log
+HAVE_ASPRINTF="yes"
+echo "HAVE_ASPRINTF=$HAVE_ASPRINTF" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"HAVE_ASPRINTF\"] = \"$HAVE_ASPRINTF\"" &amp;gt;&amp;gt;configure.lua
+echo "#ifndef HAVE_ASPRINTF" &amp;gt; $BLD/include/agar/config/have_asprintf.h
+echo "#define HAVE_ASPRINTF \"$HAVE_ASPRINTF\"" &amp;gt;&amp;gt; $BLD/include/agar/config/have_asprintf.h
+echo "#endif" &amp;gt;&amp;gt; $BLD/include/agar/config/have_asprintf.h
+echo "hdefs[\"HAVE_ASPRINTF\"] = \"$HAVE_ASPRINTF\"" &amp;gt;&amp;gt;configure.lua
+else
+echo "no"
+echo "no" &amp;gt;&amp;gt; config.log
+HAVE_ASPRINTF="no"
+echo "HAVE_ASPRINTF=$HAVE_ASPRINTF" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"HAVE_ASPRINTF\"] = \"$HAVE_ASPRINTF\"" &amp;gt;&amp;gt;configure.lua
+echo "#undef HAVE_ASPRINTF" &amp;gt;$BLD/include/agar/config/have_asprintf.h
+echo "hdefs[\"HAVE_ASPRINTF\"] = nil" &amp;gt;&amp;gt;configure.lua
+fi;
+if [ "${cache}" != "" ]; then
+echo "$HAVE_ASPRINTF" &amp;gt; ${cache}/ctest-HAVE_ASPRINTF
+echo $MK_COMPILE_STATUS &amp;gt; ${cache}/ctest-status-HAVE_ASPRINTF
+fi
+rm -f conftest.c $testdir/conftest
 $ECHO_N "checking for the snprintf() function..."
 $ECHO_N "checking for the snprintf() function..." &amp;gt;&amp;gt; config.log
 MK_CACHED="No"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -7022,6 +7082,224 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "DB4_LIBS=$DB4_LIBS" &amp;gt;&amp;gt;Makefile.config
 echo "mdefs[\"DB4_LIBS\"] = \"$DB4_LIBS\"" &amp;gt;&amp;gt;configure.lua
 fi
+if [ "${with_mysql}" != "no" ]
+ then
+$ECHO_N "checking for MySQL (http://dev.mysql.com/)..."
+$ECHO_N "checking for MySQL (http://dev.mysql.com/)..." &amp;gt;&amp;gt; config.log
+MK_EXEC_FOUND="No"
+MK_CACHED="No"
+MK_EXEC_UNIQUE="No"
+MK_EXEC_FOUND_PATH=""
+if [ "${cache}" != "" ]; then
+if [ -e "${cache}/exec-MYSQL_VERSION" ]; then
+MYSQL_VERSION=`cat ${cache}/exec-MYSQL_VERSION`
+MK_EXEC_FOUND=`cat ${cache}/exec-found-MYSQL_VERSION`
+MK_EXEC_FOUND_PATH=`cat ${cache}/exec-found-path-MYSQL_VERSION`
+MK_CACHED="Yes"
+fi
+fi
+if [ "${MK_CACHED}" = "No" ]; then
+MYSQL_VERSION=""
+for path in `echo $PATH | sed 's/:/ /g'`; do
+if [ -e "${path}/mysql_config" ]; then
+if [ "$MK_EXEC_FOUND" = "Yes" ]; then
+echo "yes."
+echo "* Warning: Multiple 'mysql_config' exist in PATH (using $MK_EXEC_FOUND_PATH)"
+echo "* Warning: Multiple 'mysql_config' exist in PATH (using $MK_EXEC_FOUND_PATH)" &amp;gt;&amp;gt; config.log
+break
+fi
+MYSQL_VERSION=`${path}/mysql_config --version`
+MK_EXEC_FOUND="Yes"
+MK_EXEC_FOUND_PATH="${path}/mysql_config"
+fi
+done
+if [ "${cache}" != "" ]; then
+echo "$MYSQL_VERSION" &amp;gt; ${cache}/exec-MYSQL_VERSION
+echo $MK_EXEC_FOUND &amp;gt; ${cache}/exec-found-MYSQL_VERSION
+echo $MK_EXEC_FOUND_PATH &amp;gt; ${cache}/exec-found-path-MYSQL_VERSION
+fi
+fi
+if [ "${MYSQL_VERSION}" != "" ]; then
+if [ "" != "" ]; then
+echo "yes ($MYSQL_VERSION in )"
+echo "yes ($MYSQL_VERSION in )" &amp;gt;&amp;gt; config.log
+else
+echo "yes ($MYSQL_VERSION)"
+echo "yes ($MYSQL_VERSION)" &amp;gt;&amp;gt; config.log
+fi;
+if [ "${prefix_mysql}" != "" ]; then
+MK_VERSION_MAJOR=`echo "$MYSQL_VERSION" |sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\).*/\1/'`;
+MK_VERSION_OK="no"
+if [ $MK_VERSION_MAJOR -gt ${prefix_mysql} ]; then
+MK_VERSION_OK="yes";
+elif [ $MK_VERSION_MAJOR -ge ${prefix_mysql} ]; then
+MK_VERSION_OK="yes";
+fi
+if [ "${MK_VERSION_OK}" != "yes" ]; then
+echo "Version ${prefix_mysql} or greater is required (found $MYSQL_VERSION)"
+exit 1
+fi;
+fi;
+$ECHO_N "checking whether MySQL works..."
+$ECHO_N "checking whether MySQL works..." &amp;gt;&amp;gt; config.log
+MK_EXEC_FOUND="No"
+MK_CACHED="No"
+if [ "${cache}" != "" ]; then
+if [ -e "${cache}/exec-MYSQL_CFLAGS" ]; then
+MYSQL_CFLAGS=`cat ${cache}/exec-MYSQL_CFLAGS`
+MK_EXEC_FOUND=`cat ${cache}/exec-found-MYSQL_CFLAGS`
+MK_CACHED="Yes"
+fi
+fi
+if [ "${MK_CACHED}" = "No" ]; then
+MYSQL_CFLAGS=""
+for path in `echo $PATH | sed 's/:/ /g'`; do
+if [ -e "${path}/mysql_config" ]; then
+MYSQL_CFLAGS=`${path}/mysql_config --cflags`
+MK_EXEC_FOUND="Yes"
+break
+fi
+done
+if [ "${cache}" != "" ]; then
+echo "$MYSQL_CFLAGS" &amp;gt; ${cache}/exec-MYSQL_CFLAGS
+echo $MK_EXEC_FOUND &amp;gt; ${cache}/exec-found-MYSQL_CFLAGS
+fi
+fi
+MK_EXEC_FOUND="No"
+MK_CACHED="No"
+if [ "${cache}" != "" ]; then
+if [ -e "${cache}/exec-MYSQL_LIBS" ]; then
+MYSQL_LIBS=`cat ${cache}/exec-MYSQL_LIBS`
+MK_EXEC_FOUND=`cat ${cache}/exec-found-MYSQL_LIBS`
+MK_CACHED="Yes"
+fi
+fi
+if [ "${MK_CACHED}" = "No" ]; then
+MYSQL_LIBS=""
+for path in `echo $PATH | sed 's/:/ /g'`; do
+if [ -e "${path}/mysql_config" ]; then
+MYSQL_LIBS=`${path}/mysql_config --libs`
+MK_EXEC_FOUND="Yes"
+break
+fi
+done
+if [ "${cache}" != "" ]; then
+echo "$MYSQL_LIBS" &amp;gt; ${cache}/exec-MYSQL_LIBS
+echo $MK_EXEC_FOUND &amp;gt; ${cache}/exec-found-MYSQL_LIBS
+fi
+fi
+MK_CACHED="No"
+MK_COMPILE_STATUS="OK"
+if [ "${cache}" != "" ]; then
+if [ -e "${cache}/ctest-HAVE_MYSQL" ]; then
+HAVE_MYSQL=`cat ${cache}/ctest-HAVE_MYSQL`
+MK_COMPILE_STATUS=`cat ${cache}/ctest-status-HAVE_MYSQL`
+MK_CACHED="Yes"
+fi
+fi
+if [ "${MK_CACHED}" = "No" ]; then
+cat &amp;lt;&amp;lt; EOT &amp;gt; conftest.c
+#include &amp;lt;mysql.h&amp;gt;
+#include &amp;lt;string.h&amp;gt;
+
+int
+main(int argc, char *argv[])
+{
+MYSQL *my = mysql_init(NULL);
+if (my != NULL) { mysql_close(my); }
+return (0);
+}
+
+EOT
+echo "$CC $CFLAGS $TEST_CFLAGS ${MYSQL_CFLAGS} -o $testdir/conftest conftest.c ${MYSQL_LIBS}" &amp;gt;&amp;gt;config.log
+$CC $CFLAGS $TEST_CFLAGS ${MYSQL_CFLAGS} -o $testdir/conftest conftest.c ${MYSQL_LIBS} 2&amp;gt;&amp;gt;config.log
+if [ $? != 0 ]; then
+echo "-&amp;gt; failed ($?)" &amp;gt;&amp;gt; config.log
+MK_COMPILE_STATUS="FAIL($?)"
+fi
+fi
+if [ "${MK_COMPILE_STATUS}" = "OK" ]; then
+echo "yes"
+echo "yes" &amp;gt;&amp;gt; config.log
+HAVE_MYSQL="yes"
+echo "HAVE_MYSQL=$HAVE_MYSQL" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"HAVE_MYSQL\"] = \"$HAVE_MYSQL\"" &amp;gt;&amp;gt;configure.lua
+echo "#ifndef HAVE_MYSQL" &amp;gt; $BLD/include/agar/config/have_mysql.h
+echo "#define HAVE_MYSQL \"$HAVE_MYSQL\"" &amp;gt;&amp;gt; $BLD/include/agar/config/have_mysql.h
+echo "#endif" &amp;gt;&amp;gt; $BLD/include/agar/config/have_mysql.h
+echo "hdefs[\"HAVE_MYSQL\"] = \"$HAVE_MYSQL\"" &amp;gt;&amp;gt;configure.lua
+else
+echo "no"
+echo "no" &amp;gt;&amp;gt; config.log
+HAVE_MYSQL="no"
+echo "HAVE_MYSQL=$HAVE_MYSQL" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"HAVE_MYSQL\"] = \"$HAVE_MYSQL\"" &amp;gt;&amp;gt;configure.lua
+echo "#undef HAVE_MYSQL" &amp;gt;$BLD/include/agar/config/have_mysql.h
+echo "hdefs[\"HAVE_MYSQL\"] = nil" &amp;gt;&amp;gt;configure.lua
+fi;
+if [ "${cache}" != "" ]; then
+echo "$HAVE_MYSQL" &amp;gt; ${cache}/ctest-HAVE_MYSQL
+echo $MK_COMPILE_STATUS &amp;gt; ${cache}/ctest-status-HAVE_MYSQL
+fi
+rm -f conftest.c $testdir/conftest$EXECSUFFIX
+if [ "${HAVE_MYSQL}" = "yes" ]; then
+echo "MYSQL_CFLAGS=$MYSQL_CFLAGS" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"MYSQL_CFLAGS\"] = \"$MYSQL_CFLAGS\"" &amp;gt;&amp;gt;configure.lua
+echo "#ifndef MYSQL_CFLAGS" &amp;gt; $BLD/include/agar/config/mysql_cflags.h
+echo "#define MYSQL_CFLAGS \"$MYSQL_CFLAGS\"" &amp;gt;&amp;gt; $BLD/include/agar/config/mysql_cflags.h
+echo "#endif" &amp;gt;&amp;gt; $BLD/include/agar/config/mysql_cflags.h
+echo "hdefs[\"MYSQL_CFLAGS\"] = \"$MYSQL_CFLAGS\"" &amp;gt;&amp;gt;configure.lua
+echo "MYSQL_LIBS=$MYSQL_LIBS" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"MYSQL_LIBS\"] = \"$MYSQL_LIBS\"" &amp;gt;&amp;gt;configure.lua
+echo "#ifndef MYSQL_LIBS" &amp;gt; $BLD/include/agar/config/mysql_libs.h
+echo "#define MYSQL_LIBS \"$MYSQL_LIBS\"" &amp;gt;&amp;gt; $BLD/include/agar/config/mysql_libs.h
+echo "#endif" &amp;gt;&amp;gt; $BLD/include/agar/config/mysql_libs.h
+echo "hdefs[\"MYSQL_LIBS\"] = \"$MYSQL_LIBS\"" &amp;gt;&amp;gt;configure.lua
+else
+echo "#undef MYSQL_CFLAGS" &amp;gt;$BLD/include/agar/config/mysql_cflags.h
+echo "hdefs[\"MYSQL_CFLAGS\"] = nil" &amp;gt;&amp;gt;configure.lua
+MYSQL_CFLAGS=""
+echo "#undef MYSQL_LIBS" &amp;gt;$BLD/include/agar/config/mysql_libs.h
+echo "hdefs[\"MYSQL_LIBS\"] = nil" &amp;gt;&amp;gt;configure.lua
+MYSQL_LIBS=""
+fi;
+else
+if [ "" != "" ]; then
+echo "no (not in )"
+echo "no (not in )" &amp;gt;&amp;gt; config.log
+else
+echo "no"
+echo "no" &amp;gt;&amp;gt; config.log
+fi;
+echo "#undef MYSQL_CFLAGS" &amp;gt;$BLD/include/agar/config/mysql_cflags.h
+echo "hdefs[\"MYSQL_CFLAGS\"] = nil" &amp;gt;&amp;gt;configure.lua
+echo "#undef MYSQL_LIBS" &amp;gt;$BLD/include/agar/config/mysql_libs.h
+echo "hdefs[\"MYSQL_LIBS\"] = nil" &amp;gt;&amp;gt;configure.lua
+fi;
+if [ "${HAVE_MYSQL}" != "yes" ]
+ then
+if [ "${with_mysql}" = "yes" ]
+ then
+echo "*"
+echo "* --with-mysql was requested, but libmysqlclient"
+echo "* was not found."
+echo "*"
+exit 1
+else
+echo "#undef HAVE_MYSQL" &amp;gt;$BLD/include/agar/config/have_mysql.h
+echo "hdefs[\"HAVE_MYSQL\"] = nil" &amp;gt;&amp;gt;configure.lua
+fi
+fi
+else
+echo "#undef HAVE_MYSQL" &amp;gt;$BLD/include/agar/config/have_mysql.h
+echo "hdefs[\"HAVE_MYSQL\"] = nil" &amp;gt;&amp;gt;configure.lua
+MYSQL_CFLAGS=""
+echo "MYSQL_CFLAGS=$MYSQL_CFLAGS" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"MYSQL_CFLAGS\"] = \"$MYSQL_CFLAGS\"" &amp;gt;&amp;gt;configure.lua
+MYSQL_LIBS=""
+echo "MYSQL_LIBS=$MYSQL_LIBS" &amp;gt;&amp;gt;Makefile.config
+echo "mdefs[\"MYSQL_LIBS\"] = \"$MYSQL_LIBS\"" &amp;gt;&amp;gt;configure.lua
+fi
 if [ "${enable_threads}" != "no" ]
  then
 $ECHO_N "checking for POSIX threads..."
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -9311,7 +9589,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "CXXFLAGS=$CXXFLAGS" &amp;gt;&amp;gt;Makefile.config
 echo "mdefs[\"CXXFLAGS\"] = \"$CXXFLAGS\"" &amp;gt;&amp;gt;configure.lua
 config_script_out="agar-config"
-config_script_cflags="-I${INCLDIR} ${SDL_CFLAGS} ${FREETYPE_CFLAGS} ${OPENGL_CFLAGS} ${X11_CFLAGS} ${GLX_CFLAGS} ${XINERAMA_CFLAGS} ${MATH_CFLAGS} ${PNG_CFLAGS} ${PTHREADS_CFLAGS} ${DB4_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}"
+config_script_cflags="-I${INCLDIR} ${SDL_CFLAGS} ${FREETYPE_CFLAGS} ${OPENGL_CFLAGS} ${X11_CFLAGS} ${GLX_CFLAGS} ${XINERAMA_CFLAGS} ${MATH_CFLAGS} ${PNG_CFLAGS} ${PTHREADS_CFLAGS} ${DB4_CFLAGS} ${MYSQL_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}"
 config_script_libs="-L${LIBDIR} -lag_gui -lag_core ${SDL_LIBS} ${FREETYPE_LIBS} ${OPENGL_LIBS} ${X11_LIBS} ${XINERAMA_LIBS} ${MATH_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}"
 # Avoid breakage with existing trees compiled before BSDBuild 2.8.
 if [ -d "$config_script_out" ]; then
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -9393,7 +9671,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 EOT
 config_script_out="agar-core-config"
 config_script_cflags="-I${INCLDIR} ${SDL_CFLAGS} ${MATH_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}"
-config_script_libs="-L${LIBDIR} -lag_core ${MATH_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}"
+config_script_libs="-L${LIBDIR} -lag_core ${MATH_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${MYSQL_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}"
 # Avoid breakage with existing trees compiled before BSDBuild 2.8.
 if [ -d "$config_script_out" ]; then
 echo "rm -fR $config_script_out"

Modified: trunk/configure.in
===================================================================
--- trunk/configure.in2012-04-06 02:13:13 UTC (rev 9096)
+++ trunk/configure.in2012-04-06 02:14:53 UTC (rev 9097)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -11,18 +11,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 RELEASE("A Mild Breeze Upon The Brow Of The Dead")
 
 # Register options for configure --help
-REGISTER_SECTION("Options specific to Agar:")
-REGISTER("--enable-&amp;lt;library&amp;gt;","Build libraries (gui|vg|rg|math|dev) [all]")
-REGISTER("--enable-debug","General debugging [no]")
-REGISTER("--enable-legacy","Deprecated interfaces [yes]")
-REGISTER("--enable-network","Network I/O support in Agar-Core [check]")
-REGISTER("--enable-objdebug","Object system debugging [no]")
-REGISTER("--enable-threads","Thread safety [check]")
-REGISTER("--enable-warnings","Suggested compiler warnings [no]")
-REGISTER("--with-db4[=PREFIX]","AG_Db: Berkeley DB backend [check]")
-REGISTER("--with-pthreads[=PREFIX]", "Specify libpthreads location [check]")
+REGISTER_SECTION("Options global to Agar:")
+REGISTER("--enable-&amp;lt;library&amp;gt;","Build libraries (gui|vg|rg|math|dev) [all]")
+REGISTER("--enable-debug","General debugging [no]")
+REGISTER("--enable-legacy","Deprecated interfaces [yes]")
+REGISTER("--enable-network","Network I/O support in Agar-Core [check]")
+REGISTER("--enable-objdebug","Object system debugging [no]")
+REGISTER("--enable-threads","Thread safety [check]")
+REGISTER("--enable-warnings","Suggested compiler warnings [no]")
+REGISTER("--with-pthreads[=PREFIX]","POSIX Threads support [check]")
 
-REGISTER_SECTION("Options specific to ag_gui library:")
+REGISTER_SECTION("Options specific to AG_Db(3) interface:")
+REGISTER("--with-db4[=PREFIX]","Enable Berkeley DB backend [check]")
+REGISTER("--with-mysql[=PREFIX]","Enable MySQL backend [check]")
+
+REGISTER_SECTION("Options specific to GUI library:")
 REGISTER("--with-freetype[=PREFIX]","Enable FreeType support [check]")
 REGISTER("--with-gl[=PREFIX]","OpenGL rendering support [check]")
 REGISTER("--with-glx[=PREFIX]","GL rendering via GLX [check]")
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,13 +36,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 REGISTER("--with-xinerama[=PREFIX]","Xinerama extension support [check]")
 REGISTER("--with-wgl","GL rendering via WGL [check]")
 
-REGISTER_SECTION("Options specific to ag_math library:")
+REGISTER_SECTION("Options specific to Math library:")
 REGISTER("--with-altivec","AltiVec optimizations [check]")
 REGISTER("--with-sse","SSE[123] optimizations [no]")
 REGISTER("--with-&amp;lt;mode&amp;gt;-fp",    "Precision (single|double|quad) [double]")
 REGISTER("--with-&amp;lt;opt&amp;gt;-inline","Inline ops (sse2|sse3|altivec) [no]")
 
-REGISTER_SECTION("Options specific to ag_au library:")
+REGISTER_SECTION("Options specific to Audio library:")
 REGISTER("--enable-audio","Build audio interface library [no]")
 REGISTER("--with-sndfile[=PREFIX]","Use sndfile library [check]")
 REGISTER("--with-portaudio[=PREFIX]","Use portaudio library [check]")
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -67,6 +70,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 CHECK(getpwuid)
 CHECK(getuid)
 CHECK(strsep)
+CHECK(asprintf)
 CHECK(snprintf)
 CHECK(vsnprintf)
 CHECK(vasprintf)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -386,6 +390,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 MDEFINE(DB4_LIBS, "")
 fi
 
+# Enable MySQL backend for AG_Db if available.
+if [ "${with_mysql}" != "no" ]; then
+CHECK(mysql, ${prefix_mysql})
+if [ "${HAVE_MYSQL}" != "yes" ]; then
+if [ "${with_mysql}" = "yes" ]; then
+echo "*"
+echo "* --with-mysql was requested, but libmysqlclient"
+echo "* was not found."
+echo "*"
+exit 1
+else
+HUNDEF(HAVE_MYSQL)
+fi
+fi
+else
+HUNDEF(HAVE_MYSQL)
+MDEFINE(MYSQL_CFLAGS, "")
+MDEFINE(MYSQL_LIBS, "")
+fi
+
 # Enable threads support if POSIX threads are available.
 if [ "${enable_threads}" != "no" ]; then
 CHECK(pthreads, ${prefix_pthreads})
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -657,8 +681,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 C_INCDIR_CONFIG($BLD/include/agar/config)
 
 # Generate the "foo-config" scripts.
-CONFIG_SCRIPT(agar-config, "-I${INCLDIR} ${SDL_CFLAGS} ${FREETYPE_CFLAGS} ${OPENGL_CFLAGS} ${X11_CFLAGS} ${GLX_CFLAGS} ${XINERAMA_CFLAGS} ${MATH_CFLAGS} ${PNG_CFLAGS} ${PTHREADS_CFLAGS} ${DB4_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_gui -lag_core ${SDL_LIBS} ${FREETYPE_LIBS} ${OPENGL_LIBS} ${X11_LIBS} ${XINERAMA_LIBS} ${MATH_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
-CONFIG_SCRIPT(agar-core-config, "-I${INCLDIR} ${SDL_CFLAGS} ${MATH_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_core ${MATH_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
+CONFIG_SCRIPT(agar-config, "-I${INCLDIR} ${SDL_CFLAGS} ${FREETYPE_CFLAGS} ${OPENGL_CFLAGS} ${X11_CFLAGS} ${GLX_CFLAGS} ${XINERAMA_CFLAGS} ${MATH_CFLAGS} ${PNG_CFLAGS} ${PTHREADS_CFLAGS} ${DB4_CFLAGS} ${MYSQL_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_gui -lag_core ${SDL_LIBS} ${FREETYPE_LIBS} ${OPENGL_LIBS} ${X11_LIBS} ${XINERAMA_LIBS} ${MATH_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
+CONFIG_SCRIPT(agar-core-config, "-I${INCLDIR} ${SDL_CFLAGS} ${MATH_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} ${CLOCK_CFLAGS}", "-L${LIBDIR} -lag_core ${MATH_LIBS} ${PTHREADS_LIBS} ${DB4_LIBS} ${MYSQL_LIBS} ${GETTEXT_LIBS} ${DSO_LIBS} ${CLOCK_LIBS}")
 CONFIG_SCRIPT(agar-dev-config, "-I${INCLDIR} ${GETTEXT_CFLAGS}", "-L${LIBDIR} -lag_dev ${GETTEXT_LIBS}")
 CONFIG_SCRIPT(agar-math-config, "-I${INCLDIR} ${MATH_CFLAGS} ${GETTEXT_CFLAGS}", "-L${LIBDIR} -lag_math ${MATH_LIBS} ${GETTEXT_LIBS}")
 CONFIG_SCRIPT(agar-rg-config, "-I${INCLDIR} ${GETTEXT_CFLAGS}", "-L${LIBDIR} -lag_rg ${GETTEXT_LIBS}")
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T02:14:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1409">
    <title>Agar: r9096 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1409</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-05 22:13:13 -0400 (Thu, 05 Apr 2012)
New Revision: 9096

Added:
   trunk/core/asprintf.c
   trunk/core/asprintf.h
Modified:
   trunk/core/Makefile
   trunk/core/core.h
   trunk/core/core_pub.h
   trunk/core/error.h
   trunk/core/snprintf.c
   trunk/core/snprintf.h
   trunk/core/vasprintf.c
   trunk/core/vasprintf.h
   trunk/core/vsnprintf.c
   trunk/core/vsnprintf.h
Log:
- add Asprintf(), TryAsprintf(), TryVsnprintf().
- Snprintf() should return size_t.


Modified: trunk/core/Makefile
===================================================================
--- trunk/core/Makefile2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/Makefile2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -12,7 +12,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 SRCS=variable.c config.c core.c error.c event.c object.c prop.c rcs.c \
 timeout.c class.c cpuinfo.c load_den.c \
 data_source.c load_string.c load_version.c \
-snprintf.c vsnprintf.c vasprintf.c \
+snprintf.c vsnprintf.c vasprintf.c asprintf.c \
 net_client.c net_command.c net_fgetln.c net_server.c \
 dir.c md5.c sha1.c rmd160.c file.c string_compat.c dso.c tree.c \
 time.c time_dummy.c time_gettimeofday.c time_win32.c time_condwait.c \
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -26,7 +26,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 CFLAGS+=-D_AGAR_CORE_INTERNAL ${PTHREADS_XOPEN_CFLAGS} \
 ${ALTIVEC_CHECK_CFLAGS} ${GETTEXT_CFLAGS} ${DSO_CFLAGS} \
-${DB4_CFLAGS} ${CLOCK_CFLAGS}
+${DB4_CFLAGS} ${MYSQL_CFLAGS} ${CLOCK_CFLAGS}
 
 include .manlinks.mk
 include ${TOP}/mk/build.lib.mk

Added: trunk/core/asprintf.c
===================================================================
--- trunk/core/asprintf.c                        (rev 0)
+++ trunk/core/asprintf.c2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,139 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * Copyright (c) 2002-2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &amp;lt;config/have_asprintf.h&amp;gt;
+#include &amp;lt;config/_mk_have_sys_types_h.h&amp;gt;
+
+#if defined(__linux__) &amp;amp;&amp;amp; !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#ifdef _MK_HAVE_SYS_TYPES_H
+#include &amp;lt;sys/types.h&amp;gt;
+#endif
+#include &amp;lt;stdio.h&amp;gt;
+#include &amp;lt;stdarg.h&amp;gt;
+#include &amp;lt;string.h&amp;gt;
+
+#include "core.h"
+
+#ifndef HAVE_ASPRINTF
+
+int
+AG_TryAsprintf(char **ret, const char *fmt, ...)
+{
+char *buf, *bufNew;
+int size;
+size_t buflen;
+va_list ap;
+
+buflen = strlen(fmt) + 128;/* Guess */
+if ((buf = TryMalloc(buflen)) == NULL) {
+return (-1);
+}
+va_start(ap, fmt);
+size = vsprintf(buf, fmt, ap);
+va_end(ap);
+if (size &amp;lt;= buflen) {
+*ret = buf;
+return (size);
+}
+if ((bufNew = TryRealloc(buf, size+1)) == NULL) {
+Free(buf);
+return (-1);
+}
+buf = bufNew;
+va_start(ap, fmt);
+size = vsprintf(buf, fmt, ap);
+va_end(ap);
+*ret = buf;
+return (size);
+}
+
+void
+AG_Asprintf(char **ret, const char *fmt, ...)
+{
+char *buf, *bufNew;
+int size;
+size_t buflen;
+va_list ap;
+
+buflen = strlen(fmt) + 128;/* Guess */
+if ((buf = TryMalloc(buflen)) == NULL) {
+goto fail;
+}
+va_start(ap, fmt);
+size = vsprintf(buf, fmt, ap);
+va_end(ap);
+if (size &amp;lt;= buflen) {
+*ret = buf;
+return (size);
+}
+if ((bufNew = TryRealloc(buf, size+1)) == NULL) {
+Free(buf);
+goto fail;
+}
+buf = bufNew;
+va_start(ap, fmt);
+size = vsprintf(buf, fmt, ap);
+va_end(ap);
+*ret = buf;
+return (size);
+fail:
+AG_FatalError("asprintf: Out of memory");
+}
+
+#else /* HAVE_ASPRINTF */
+
+int
+AG_TryAsprintf(char **ret, const char *fmt, ...)
+{
+va_list ap;
+int rv;
+
+ap = va_start(fmt);
+rv = AG_Vasprintf(ret, fmt, ap);
+va_end(ap);
+
+if (rv == -1) {
+AG_SetError("asprintf: Out of memory");
+return (-1);
+}
+return (rv);
+}
+
+void
+AG_Asprintf(char **ret, const char *fmt, ...)
+{
+va_list ap;
+int rv;
+
+ap = va_start(fmt);
+rv = AG_Vasprintf(ret, fmt, ap);
+va_end(ap);
+
+if (rv == -1)
+AG_FatalError("asprintf: Out of memory");
+}
+#endif /* !HAVE_ASPRINTF */

Added: trunk/core/asprintf.h
===================================================================
--- trunk/core/asprintf.h                        (rev 0)
+++ trunk/core/asprintf.h2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*Public domain*/
+
+#ifndef_AGAR_CORE_ASPRINTF_H_
+#define_AGAR_CORE_ASPRINTF_H_
+
+#include &amp;lt;stdarg.h&amp;gt;
+#include &amp;lt;agar/core/begin.h&amp;gt;
+__BEGIN_DECLS
+
+void AG_Asprintf(char **, const char *, ...);
+int  AG_TryAsprintf(char **, const char *, ...);
+
+#if defined(_AGAR_INTERNAL) || defined(_USE_AGAR_STD)
+# define Asprintf AG_Asprintf
+# define TryAsprintf AG_TryAsprintf
+#endif /* _AGAR_INTERNAL */
+
+__END_DECLS
+#include &amp;lt;agar/core/close.h&amp;gt;
+
+#endif /* _AGAR_CORE_ASPRINTF_H_ */

Modified: trunk/core/core.h
===================================================================
--- trunk/core/core.h2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/core.h2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -53,6 +53,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;core/snprintf.h&amp;gt;
 #include &amp;lt;core/vsnprintf.h&amp;gt;
 #include &amp;lt;core/vasprintf.h&amp;gt;
+#include &amp;lt;core/asprintf.h&amp;gt;
 
 #ifndef MIN
 #defineMIN(a,b) (((a)&amp;lt;(b))?(a):(b))

Modified: trunk/core/core_pub.h
===================================================================
--- trunk/core/core_pub.h2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/core_pub.h2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -11,6 +11,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # include &amp;lt;agar/core/snprintf.h&amp;gt;
 # include &amp;lt;agar/core/vsnprintf.h&amp;gt;
 # include &amp;lt;agar/core/vasprintf.h&amp;gt;
+# include &amp;lt;agar/core/asprintf.h&amp;gt;
 #endif
 
 #include &amp;lt;agar/core/data_source.h&amp;gt;

Modified: trunk/core/error.h
===================================================================
--- trunk/core/error.h2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/error.h2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -36,13 +36,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # define Free(p) AG_Free(p)
 # define Realloc(p,len) AG_Realloc((p),(len))
 # define TryRealloc(p,len) AG_TryRealloc((p),(len))
-# define Snprintf AG_Snprintf
-# define Vsnprintf AG_Vsnprintf
-# define Vasprintf(msg, fmt, args) do {\
-if (AG_Vasprintf((msg),(fmt),(args)) == -1) \
-AG_FatalError("Out of memory (vasprintf)");\
-} while (0)
-# define TryVasprintf(msg, fmt, args) AG_Vasprintf((msg),(fmt),(args))
 # define Verbose AG_Verbose
 # ifdef AG_DEBUG
 #  define Debug AG_Debug

Modified: trunk/core/snprintf.c
===================================================================
--- trunk/core/snprintf.c2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/snprintf.c2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -66,13 +66,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 #include "snprintf.h"
 
-#ifndef MAX
-#define MAX(a,b) (((a) &amp;gt; (b)) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a,b) (((a) &amp;lt; (b)) ? (a) : (b))
-#endif
-
 static void dopr(char *, size_t, const char *, va_list);
 static void fmtstr(char *, size_t *, size_t, char *, int, int, int);
 static void fmtint(char *, size_t *, size_t, long, int, int, int, int);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -486,7 +479,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if (spadlen &amp;lt; 0)
 spadlen = 0;
 if (flags &amp;amp; DP_F_ZERO) {
-zpadlen = MAX(zpadlen, spadlen);
+zpadlen = AG_MAX(zpadlen, spadlen);
 spadlen = 0;
 }
 if (flags &amp;amp; DP_F_MINUS) 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -675,7 +668,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 buffer[(*currlen)++] = c;
 }
 
-int 
+size_t
 AG_Snprintf(char *str, size_t count, const char *fmt, ...)
 {
 va_list ap;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -684,7 +677,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 str[0] = 0;
 dopr(str, count, fmt, ap);
 va_end(ap);
-return (int)strlen(str);
+return strlen(str);
 }
 
 #endif /* HAVE_SNPRINTF */

Modified: trunk/core/snprintf.h
===================================================================
--- trunk/core/snprintf.h2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/snprintf.h2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -8,6 +8,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;sys/types.h&amp;gt;
 #endif
 
+#if defined(_AGAR_INTERNAL) || defined(_USE_AGAR_STD)
+# define Snprintf AG_Snprintf
+#endif /* _AGAR_INTERNAL */
+
 #include &amp;lt;agar/config/have_snprintf.h&amp;gt;
 #ifdef HAVE_SNPRINTF
 # include &amp;lt;stdio.h&amp;gt;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,9 +23,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #else
 # include &amp;lt;agar/core/begin.h&amp;gt;
 __BEGIN_DECLS
-int AG_Snprintf(char *, size_t, const char *, ...);
+size_t AG_Snprintf(char *, size_t, const char *, ...);
 __END_DECLS
 # include &amp;lt;agar/core/close.h&amp;gt;
 #endif /* !HAVE_SNPRINTF */
-
 #endif /* _AGAR_CORE_SNPRINTF_H_ */

Modified: trunk/core/vasprintf.c
===================================================================
--- trunk/core/vasprintf.c2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/vasprintf.c2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -41,7 +41,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include "core.h"
 
 int
-AG_Vasprintf(char **ret, const char *fmt, va_list ap)
+AG_TryVasprintf(char **ret, const char *fmt, va_list ap)
 {
 #ifndef HAVE_VASPRINTF
 char *buf;

Modified: trunk/core/vasprintf.h
===================================================================
--- trunk/core/vasprintf.h2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/vasprintf.h2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,13 +2,24 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 #ifndef_AGAR_CORE_VASPRINTF_H_
 #define_AGAR_CORE_VASPRINTF_H_
-
 #include &amp;lt;stdarg.h&amp;gt;
-
 #include &amp;lt;agar/core/begin.h&amp;gt;
 __BEGIN_DECLS
-int AG_Vasprintf(char **, const char *, va_list);
+
+int AG_TryVasprintf(char **, const char *, va_list);
+
+static __inline__ void
+AG_Vasprintf(char **msg, const char *fmt, va_list args)
+{
+if (AG_TryVasprintf(msg, fmt, args) == -1) 
+AG_FatalError(NULL);
+}
+
+#if defined(_AGAR_INTERNAL) || defined(_USE_AGAR_STD)
+# define Vasprintf AG_Vasprintf
+# define TryVasprintf AG_TryVasprintf
+#endif /* _AGAR_INTERNAL */
+
 __END_DECLS
 #include &amp;lt;agar/core/close.h&amp;gt;
-
 #endif /* _AGAR_CORE_VASPRINTF_H_ */

Modified: trunk/core/vsnprintf.c
===================================================================
--- trunk/core/vsnprintf.c2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/vsnprintf.c2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -56,22 +56,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  *    acceptable.  Consider stealing from mutt or enlightenment.
  **************************************************************/
 
+#include &amp;lt;core/core.h&amp;gt;
+#include &amp;lt;stdio.h&amp;gt;
+#include "vsnprintf.h"
+
 #include &amp;lt;config/have_vsnprintf.h&amp;gt;
 #ifndef HAVE_VSNPRINTF
 
-#include &amp;lt;core/core.h&amp;gt;
-
-#include "vsnprintf.h"
-
 #include &amp;lt;ctype.h&amp;gt;
 
-#ifndef MAX
-#define MAX(a,b) (((a) &amp;gt; (b)) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a,b) (((a) &amp;lt; (b)) ? (a) : (b))
-#endif
-
 static void dopr(char *, size_t, const char *, va_list);
 static void fmtstr(char *, size_t *, size_t, char *, int, int, int);
 static void fmtint(char *, size_t *, size_t, long, int, int, int, int);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -475,7 +468,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if (spadlen &amp;lt; 0)
 spadlen = 0;
 if (flags &amp;amp; DP_F_ZERO) {
-zpadlen = MAX(zpadlen, spadlen);
+zpadlen = AG_MAX(zpadlen, spadlen);
 spadlen = 0;
 }
 if (flags &amp;amp; DP_F_MINUS) 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -665,11 +658,29 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 
 int 
-AG_Vsnprintf(char *str, size_t count, const char *fmt, va_list ap)
+AG_TryVsnprintf(char *str, size_t count, const char *fmt, va_list ap)
 {
 str[0] = 0;
 dopr(str, count, fmt, ap);
-return (strlen(str));
+return (0);
 }
 
+#else /* !HAVE_VSNPRINTF */
+
+int 
+AG_TryVsnprintf(char *str, size_t count, const char *fmt, va_list ap)
+{
+int rv;
+#ifdef _XBOX
+rv = _vsnprintf(str, count, fmt, ap);
+#else
+rv = vsnprintf(str, count, fmt, ap);
+#endif
+if (rv == -1) {
+AG_SetError("vsnprintf: Out of memory");
+return (-1);
+}
+return (0);
+}
+
 #endif /* HAVE_VSNPRINTF */

Modified: trunk/core/vsnprintf.h
===================================================================
--- trunk/core/vsnprintf.h2012-04-06 02:09:38 UTC (rev 9095)
+++ trunk/core/vsnprintf.h2012-04-06 02:13:13 UTC (rev 9096)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,28 +2,29 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 #ifndef_AGAR_CORE_VSNPRINTF_H_
 #define_AGAR_CORE_VSNPRINTF_H_
-
 #include &amp;lt;agar/config/_mk_have_sys_types_h.h&amp;gt;
-#include &amp;lt;agar/config/have_vsnprintf.h&amp;gt;
-
 #ifdef _MK_HAVE_SYS_TYPES_H
 #include &amp;lt;sys/types.h&amp;gt;
 #endif
 #include &amp;lt;stdarg.h&amp;gt;
 
-#ifdef HAVE_VSNPRINTF
-# include &amp;lt;stdio.h&amp;gt;
-#ifdef _XBOX
-# define AG_Vsnprintf _vsnprintf
-#else
-# define AG_Vsnprintf vsnprintf
-#endif // _XBOX
-#else
-# include &amp;lt;agar/core/begin.h&amp;gt;
+#include &amp;lt;agar/core/begin.h&amp;gt;
 __BEGIN_DECLS
-int AG_Vsnprintf(char *, size_t, const char *, va_list);
+
+int AG_TryVsnprintf(char *, size_t, const char *, va_list);
+
+static __inline__ void
+AG_Vsnprintf(char *msg, size_t len, const char *fmt, va_list args)
+{
+if (AG_TryVsnprintf(msg, len, fmt, args) == -1)
+AG_FatalError(NULL);
+}
+
+#if defined(_AGAR_INTERNAL) || defined(_USE_AGAR_STD)
+# define Vsnprintf AG_Vsnprintf
+# define TryVsnprintf AG_TryVsnprintf
+#endif /* _AGAR_INTERNAL */
+
 __END_DECLS
-# include &amp;lt;agar/core/close.h&amp;gt;
-#endif /* HAVE_VASPRINTF */
-
+#include &amp;lt;agar/core/close.h&amp;gt;
 #endif /* _AGAR_CORE_VSNPRINTF_H_ */
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T02:13:13</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1408">
    <title>Agar: r9095 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1408</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-04-05 22:09:38 -0400 (Thu, 05 Apr 2012)
New Revision: 9095

Modified:
   trunk/core/db.h
   trunk/core/db_bdb.c
   trunk/core/db_mysql.c
Log:
unbreak



Modified: trunk/core/db.h
===================================================================
--- trunk/core/db.h2012-04-05 05:34:22 UTC (rev 9094)
+++ trunk/core/db.h2012-04-06 02:09:38 UTC (rev 9095)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -20,8 +20,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 size_t keySize, dataSize;
 } AG_DbEntry;
 
-typedef void (*AG_DbIterateFn)(void *db, void *key, size_t keySize,
-                               void *data, size_t dataSize);
+typedef int (*AG_DbIterateFn)(AG_DbEntry *, void *);
 
 typedef struct ag_db_class {
 struct ag_object_class _inherit;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -43,7 +42,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 int  (*get)(void *, AG_DbEntry *);
 int  (*put)(void *, AG_DbEntry *);
 int  (*del)(void *, AG_DbEntry *);
-int  (*iterate)(void *, AG_DbIterateFn);
+int  (*iterate)(void *, AG_DbIterateFn, void *);
 } AG_DbClass;
 
 #define AGDB_CLASS(db) ((AG_DbClass *)AGOBJECT(db)-&amp;gt;cls)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -122,13 +121,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 /* Iterate over all entries. */
 static __inline__ int
-AG_DbIterate(AG_Db *db, AG_DbIterateFn fn)
+AG_DbIterate(AG_Db *db, AG_DbIterateFn fn, void *arg)
 {
 AG_DbClass *dbc = AGDB_CLASS(db);
 int rv;
 
 AG_ObjectLock(db);
-rv = dbc-&amp;gt;iterate(db, fn);
+rv = dbc-&amp;gt;iterate(db, fn, arg);
 AG_ObjectUnlock(db);
 return (rv);
 }

Modified: trunk/core/db_bdb.c
===================================================================
--- trunk/core/db_bdb.c2012-04-05 05:34:22 UTC (rev 9094)
+++ trunk/core/db_bdb.c2012-04-06 02:09:38 UTC (rev 9095)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -41,7 +41,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 static const struct {
 const char *name;
 Uint32 mask;
-} agBDBOptions[] = {
+} bdbOptions[] = {
 { "db-create",DB_CREATE },
 { "db-create-excl",DB_EXCL },
 { "db-auto-commit",DB_AUTO_COMMIT },
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -57,43 +57,43 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 { "db-read-uncommitted",DB_READ_UNCOMMITTED },
 #endif
 };
-static const int agBDBOptionCount = sizeof(agBDBOptions)/sizeof(agBDBOptions[0]);
+static const int bdbOptionCount = sizeof(bdbOptions)/sizeof(bdbOptions[0]);
 
 static void
 Init(void *obj)
 {
-AG_DbHashBT *hbt = obj;
+AG_DbHashBT *db = obj;
 int i;
 
-for (i = 0; i &amp;lt; ag; i++)
-AG_SetInt(hbt, agBDBOptions[i].name, 0);
+for (i = 0; i &amp;lt; bdbOptionCount; i++)
+AG_SetInt(db, bdbOptions[i].name, 0);
 }
 
 static int
 Open(void *obj, const char *path, Uint flags)
 {
-AG_DbHashBT *hbt = obj;
+AG_DbHashBT *db = obj;
 Uint32 dbFlags = 0;
 int i, rv;
 DBTYPE dbtype;
 
-if (strcmp(AGDB_OPS(hbt)-&amp;gt;name, "hash") == 0) {
+if (strcmp(AGDB_CLASS(db)-&amp;gt;name, "hash") == 0) {
 dbtype = DB_HASH;
 } else {
 dbtype = DB_BTREE;
 }
-if ((rv = db_create(&amp;amp;hbt-&amp;gt;pDB, NULL, 0)) != 0) {
+if ((rv = db_create(&amp;amp;db-&amp;gt;pDB, NULL, 0)) != 0) {
 AG_SetError("db_create: %s", db_strerror(rv));
 return (-1);
 }
-for (i = 0; i &amp;lt; agBDBOptionsCount; i++) {
-if (AG_GetInt(hbt, agBDBOptions[i].name))
-dbFlags |= agBDBOptions[i].mask;
+for (i = 0; i &amp;lt; bdbOptionCount; i++) {
+if (AG_GetInt(db, bdbOptions[i].name))
+dbFlags |= bdbOptions[i].mask;
 }
 if (flags &amp;amp; AG_DB_READONLY) {
 dbFlags |= DB_RDONLY;
 }
-rv = hbt-&amp;gt;pDB-&amp;gt;open(hbt-&amp;gt;pDB, NULL, path, dbtype, dbFlags, 0);
+rv = db-&amp;gt;pDB-&amp;gt;open(db-&amp;gt;pDB, NULL, path, NULL, dbtype, dbFlags, 0);
 if (rv != 0) {
 AG_SetError("db_open %s: %s", path, db_strerror(rv));
 return (-1);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -104,20 +104,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 static void
 Close(void *obj)
 {
-AG_DbHashBT *hbt = obj;
+AG_DbHashBT *db = obj;
 int rv;
 
-if ((rv = hbt-&amp;gt;pDB-&amp;gt;close(hbt-&amp;gt;pDB, 0)) != 0)
+if ((rv = db-&amp;gt;pDB-&amp;gt;close(db-&amp;gt;pDB, 0)) != 0)
 AG_Verbose("db_close: %s; ignoring", db_strerror(rv));
 }
 
 static int
 Sync(void *obj)
 {
-AG_DbHashBT *hbt = obj;
+AG_DbHashBT *db = obj;
 int rv;
 
-if ((rv = hbt-&amp;gt;pDB-&amp;gt;sync(hbt-&amp;gt;pDB, 0)) != 0) {
+if ((rv = db-&amp;gt;pDB-&amp;gt;sync(db-&amp;gt;pDB, 0)) != 0) {
 AG_SetError("db_sync: %s", db_strerror(rv));
 return (-1);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -127,14 +127,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 static int
 Exists(void *obj, AG_DbEntry *dbe)
 {
-AG_DbHashBT *hbt = obj;
+AG_DbHashBT *db = obj;
 DBT key;
 int rv;
 
 memset(&amp;amp;key, 0, sizeof(DBT));
-key.data = dbe-&amp;gt;keyData;
+key.data = dbe-&amp;gt;key;
 key.size = dbe-&amp;gt;keySize;
-if ((rv = hbt-&amp;gt;pDB-&amp;gt;exists(hbt-&amp;gt;pDB, NULL, &amp;amp;key, 0)) != DB_NOTFOUND) {
+if ((rv = db-&amp;gt;pDB-&amp;gt;exists(db-&amp;gt;pDB, NULL, &amp;amp;key, 0)) != DB_NOTFOUND) {
 return (1);
 }
 return (0);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -143,15 +143,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 static int
 Get(void *obj, AG_DbEntry *dbe)
 {
-AG_DbHashBT *hbt = obj;
+AG_DbHashBT *db = obj;
 DBT key, data;
 int rv;
 
 memset(&amp;amp;key, 0, sizeof(DBT));
 memset(&amp;amp;data, 0, sizeof(DBT));
-key.data = keyData;
-key.size = keySize;
-if ((rv = hbt-&amp;gt;pDB-&amp;gt;get(hbt-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) != 0) {
+key.data = dbe-&amp;gt;key;
+key.size = dbe-&amp;gt;keySize;
+if ((rv = db-&amp;gt;pDB-&amp;gt;get(db-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) != 0) {
 AG_SetError("db_get: %s", db_strerror(rv));
 return (-1);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -165,7 +165,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 static int
 Put(void *obj, AG_DbEntry *dbe)
 {
-AG_DbHashBT *hbt = obj;
+AG_DbHashBT *db = obj;
 DBT key, data;
 int rv;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -175,7 +175,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 memset(&amp;amp;data, 0, sizeof(DBT));
 data.data = dbe-&amp;gt;data;
 data.size = dbe-&amp;gt;dataSize;
-if ((rv = hbt-&amp;gt;pDB-&amp;gt;put(hbt-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) != 0) {
+if ((rv = db-&amp;gt;pDB-&amp;gt;put(db-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) != 0) {
 AG_SetError("db_put: %s", db_strerror(rv));
 return (-1);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -185,21 +185,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 static int
 Del(void *obj, AG_DbEntry *dbe)
 {
-AG_DbHashBT *hbt = obj;
-DBT key, data;
+AG_DbHashBT *db = obj;
+DBT key;
 int rv;
 
-memset(&amp;amp;key, 0, sizeof(DBT));
-memset(&amp;amp;data, 0, sizeof(DBT));
-key.data = keyData;
-key.size = keySize;
 #if 0
-if ((rv = hbt-&amp;gt;pDB-&amp;gt;get(hbt-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) == DB_NOTFOUND) {
+if ((rv = db-&amp;gt;pDB-&amp;gt;get(db-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) == DB_NOTFOUND) {
 AG_SetError("db_del: No such entry");
 return (-1);
 }
 #endif
-if ((rv = hbt-&amp;gt;pDB-&amp;gt;del(hbt-&amp;gt;pDB, NULL, &amp;amp;key, 0)) != 0) {
+memset(&amp;amp;key, 0, sizeof(DBT));
+key.data = dbe-&amp;gt;key;
+key.size = dbe-&amp;gt;keySize;
+if ((rv = db-&amp;gt;pDB-&amp;gt;del(db-&amp;gt;pDB, NULL, &amp;amp;key, 0)) != 0) {
 AG_SetError("DB Delete: %s", db_strerror(rv));
 return (-1);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -207,27 +206,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 
 static int
-Iterate(void *obj, AG_DbIterateFn fn)
+Iterate(void *obj, AG_DbIterateFn fn, void *arg)
 {
-AG_DbHashBT *hbt = obj;
-AG_List *L;
+AG_DbHashBT *db = obj;
 DBC *c;
 DBT key, data;
 int rv;
 
-hbt-&amp;gt;pDB-&amp;gt;cursor(hbt-&amp;gt;pDB, NULL, &amp;amp;c, 0);
+db-&amp;gt;pDB-&amp;gt;cursor(db-&amp;gt;pDB, NULL, &amp;amp;c, 0);
 memset(&amp;amp;key, 0, sizeof(DBT));
 memset(&amp;amp;data, 0, sizeof(DBT));
 while ((rv = c-&amp;gt;c_get(c, &amp;amp;key, &amp;amp;data, DB_NEXT)) == 0) {
 AG_DbEntry dbe;
 
-dbe.db = db;
+dbe.db = (AG_Db *)db;
 dbe.key = key.data;
-dbe.keySize key.size;
+dbe.keySize = key.size;
 dbe.data = data.data;
 dbe.dataSize = data.size;
 
-if (fn(&amp;amp;dbe) == -1) {
+if (fn(&amp;amp;dbe, arg) == -1) {
 c-&amp;gt;c_close(c);
 return (-1);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -259,7 +257,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_DB_KEY_DATA,/* Key is variable data */
 AG_DB_REC_VARIABLE,/* Variable-sized records */
 Open,
-Close
+Close,
 Sync,
 Exists,
 Get,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -284,7 +282,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_DB_KEY_DATA,/* Key is variable data */
 AG_DB_REC_VARIABLE,/* Variable-sized records */
 Open,
-Close
+Close,
 Sync,
 Exists,
 Get,

Modified: trunk/core/db_mysql.c
===================================================================
--- trunk/core/db_mysql.c2012-04-05 05:34:22 UTC (rev 9094)
+++ trunk/core/db_mysql.c2012-04-06 02:09:38 UTC (rev 9095)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,6 +33,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;core/core.h&amp;gt;
 #include &amp;lt;db.h&amp;gt;
 #include &amp;lt;ctype.h&amp;gt;
+#include &amp;lt;mysql.h&amp;gt;
 
 typedef struct ag_db_mysql {
 struct ag_db _inherit;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -43,7 +44,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 Init(void *obj)
 {
 AG_DbMySQL *db = obj;
-int i;
 
 AG_SetString(db, "host",NULL);
 AG_SetInt(db,    "port",0);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -74,7 +74,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 static int
 Open(void *obj, const char *path, Uint flags)
 {
-char dbName[128], host[128], user[128], pass[128];
+char dbName[128];
 AG_DbMySQL *db = obj;
 MYSQL *my;
 unsigned long myFlags = CLIENT_REMEMBER_OPTIONS;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -84,7 +84,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 if ((my = mysql_init(NULL)) == NULL) {
 AG_SetError("mysql_init failed");
-return (NULL);
+return (-1);
 }
 if (path != NULL) {
 Strlcpy(dbName, path, sizeof(dbName));
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -109,11 +109,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 case 'm':i = MYSQL_PROTOCOL_MEMORY;break;
 default:i = MYSQL_PROTOCOL_DEFAULT;break;
 }
-mysql_options(my, MYSQL_OPT_PROTOCOL, &amp;amp;i);
+mysql_options(my, MYSQL_OPT_PROTOCOL, (const char *)&amp;amp;i);
 }
-if ((i = AG_GetUint(db,"read-timeout")) != 0) { mysql_options(my, MYSQL_OPT_READ_TIMEOUT, &amp;amp;i); }
-if ((i = AG_GetUint(db,"write-timeout")) != 0) { mysql_options(my, MYSQL_OPT_WRITE_TIMEOUT, &amp;amp;i); }
-if (AG_GetUint(db,"reconnect") == 1) { mysql_options(my, MYSQL_OPT_RECONNECT, &amp;amp;b); }
+if ((i = AG_GetUint(db,"read-timeout")) != 0) { mysql_options(my, MYSQL_OPT_READ_TIMEOUT, (const char *)&amp;amp;i); }
+if ((i = AG_GetUint(db,"write-timeout")) != 0) { mysql_options(my, MYSQL_OPT_WRITE_TIMEOUT, (const char *)&amp;amp;i); }
+if (AG_GetUint(db,"reconnect") == 1) { mysql_options(my, MYSQL_OPT_RECONNECT, (const char *)&amp;amp;b); }
 
 if ((s = AG_GetStringP(db,"charset")) != NULL) { mysql_options(my, MYSQL_SET_CHARSET_NAME, s); }
 if ((s = AG_GetStringP(db,"charset-dir")) != NULL) { mysql_options(my, MYSQL_SET_CHARSET_DIR, s); }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -124,10 +124,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     AG_GetStringP(my,"pass"),
     dbName,
     AG_GetInt(my,"port"),
-    AG_GetString(my,"unix-socket"),
+    AG_GetStringP(my,"unix-socket"),
     myFlags);
 if (db-&amp;gt;my == NULL) {
-AG_SetError("MySQL: %s", mysql_error(my))
+AG_SetError("MySQL: %s", mysql_error(my));
 mysql_close(my);
 return (-1);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -143,6 +143,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 db-&amp;gt;my = NULL;
 }
 
+static __inline__ char *
+EncodeKey(AG_DbEntry *dbe)
+{
+/* TODO */
+return Strdup(dbe-&amp;gt;key);
+}
+
 static int
 Exists(void *obj, AG_DbEntry *dbe)
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -157,7 +164,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return (-1);
 }
 Free(q);
-return (mysql_field_count(db-&amp;gt;my) &amp;gt; 0) ? 1 : 0
+return (mysql_field_count(db-&amp;gt;my) &amp;gt; 0) ? 1 : 0;
 }
 
 static int
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -179,7 +186,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 
 static int
-Iterate(void *obj, AG_DbIterateFn fn)
+Iterate(void *obj, AG_DbIterateFn fn, void *arg)
 {
 return (-1);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -201,7 +208,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_DB_KEY_DATA,/* Key is variable data */
 AG_DB_REC_VARIABLE,/* Variable-sized records */
 Open,
-Close
+Close,
 NULL,/* sync */
 Exists,
 Get,
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-04-06T02:09:38</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1407">
    <title>Agar: r9093 - trunk/au</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1407</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-02-23 22:18:39 -0500 (Thu, 23 Feb 2012)
New Revision: 9093

Modified:
   trunk/au/au_dev_file.c
   trunk/au/au_dev_pa.c
Log:
use AG_ThreadTryCreate()



Modified: trunk/au/au_dev_file.c
===================================================================
--- trunk/au/au_dev_file.c2012-02-24 03:18:32 UTC (rev 9092)
+++ trunk/au/au_dev_file.c2012-02-24 03:18:39 UTC (rev 9093)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -131,7 +131,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_SetError("%s(%d): %s", path, rate, sf_strerror(NULL));
 return (-1);
 }
-if (AG_ThreadCreate(&amp;amp;df-&amp;gt;th, AU_DevFileThread, df) != 0) {
+if (AG_ThreadTryCreate(&amp;amp;df-&amp;gt;th, AU_DevFileThread, df) != 0) {
 sf_write_sync(df-&amp;gt;file);
 sf_close(df-&amp;gt;file);
 df-&amp;gt;file = NULL;

Modified: trunk/au/au_dev_pa.c
===================================================================
--- trunk/au/au_dev_pa.c2012-02-24 03:18:32 UTC (rev 9092)
+++ trunk/au/au_dev_pa.c2012-02-24 03:18:39 UTC (rev 9093)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -143,7 +143,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_SetError("PortAudio error: %s", Pa_GetErrorText(rv));
 goto fail;
 }
-if (AG_ThreadCreate(&amp;amp;dpa-&amp;gt;th, AU_DevPaThread, dpa) != 0) {
+if (AG_ThreadTryCreate(&amp;amp;dpa-&amp;gt;th, AU_DevPaThread, dpa) != 0) {
 goto fail;
 }
 return (0);
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-02-24T03:18:39</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1406">
    <title>Agar: r9092 - trunk</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1406</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-02-23 22:18:32 -0500 (Thu, 23 Feb 2012)
New Revision: 9092

Modified:
   trunk/configure
   trunk/configure.in
Log:
enable db4 if available



Modified: trunk/configure
===================================================================
--- trunk/configure2012-02-24 03:17:50 UTC (rev 9091)
+++ trunk/configure2012-02-24 03:18:32 UTC (rev 9092)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -387,7 +387,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "    --enable-objdebug         Object system debugging [no]"
 echo "    --enable-threads          Thread safety [check]"
 echo "    --enable-warnings         Suggested compiler warnings [no]"
-echo "    --with-db4[=PREFIX]       Berkeley DB support in Agar-Core [check]"
+echo "    --with-db4[=PREFIX]       AG_Db: Berkeley DB backend [check]"
 echo "    --with-pthreads[=PREFIX]  Specify libpthreads location [check]"
 echo ""
 echo "Options specific to ag_gui library:"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6779,7 +6779,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 echo "hdefs[\"HAVE_GETADDRINFO\"] = nil" &amp;gt;&amp;gt;configure.lua
 fi
 
-if [ "${with_db4}" = "yes" ]
+if [ "${with_db4}" != "no" ]
  then
 $ECHO_N "checking for Berkeley DB 4.x..."
 $ECHO_N "checking for Berkeley DB 4.x..." &amp;gt;&amp;gt; config.log
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6788,7 +6788,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 DB4_VERSION=""
 
 for path in  /usr /usr/local /opt; do
-if [ -e "${path}/include/db4.7" ]; then
+if [ -e "${path}/include/db4.8" ]; then
+DB4_CFLAGS="-I${path}/include/db4.8 -I${path}/include"
+DB4_VERSION="4.8"
+elif [ -e "${path}/include/db4.7" ]; then
 DB4_CFLAGS="-I${path}/include/db4.7 -I${path}/include"
 DB4_VERSION="4.7"
 elif [ -e "${path}/include/db4.6" ]; then
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6876,6 +6879,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 DB4_LIBS="-L${path}/lib -ldb-4.7"
 fi
 ;;
+4.8)
+if [ -e "${path}/lib/db48" ]; then
+DB4_LIBS="-L${path}/lib/db48 -ldb"
+elif [ -e "${path}/lib/libdb-4.8.so" ]; then
+DB4_LIBS="-L${path}/lib -ldb-4.8"
+fi
+;;
 *)
 ;;
 esac
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6915,7 +6925,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if [ "${MK_CACHED}" = "No" ]; then
 cat &amp;lt;&amp;lt; EOT &amp;gt; conftest.c
 #include &amp;lt;db.h&amp;gt;
-
+#if DB_VERSION_MAJOR != 4
+#error version
+#endif
 int main(int argc, char *argv[]) {
 DB *db;
 db_create(&amp;amp;db, NULL, 0);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6991,7 +7003,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if [ "${with_db4}" = "yes" ]
  then
 echo "*"
-echo "* --with-db4 was requested, but Berkeley DB v4"
+echo "* --with-db4 was requested, but Berkeley DB"
 echo "* was not found."
 echo "*"
 exit 1

Modified: trunk/configure.in
===================================================================
--- trunk/configure.in2012-02-24 03:17:50 UTC (rev 9091)
+++ trunk/configure.in2012-02-24 03:18:32 UTC (rev 9092)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,7 +19,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 REGISTER("--enable-objdebug","Object system debugging [no]")
 REGISTER("--enable-threads","Thread safety [check]")
 REGISTER("--enable-warnings","Suggested compiler warnings [no]")
-REGISTER("--with-db4[=PREFIX]","Berkeley DB support in Agar-Core [check]")
+REGISTER("--with-db4[=PREFIX]","AG_Db: Berkeley DB backend [check]")
 REGISTER("--with-pthreads[=PREFIX]", "Specify libpthreads location [check]")
 
 REGISTER_SECTION("Options specific to ag_gui library:")
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -366,13 +366,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 HUNDEF(HAVE_GETADDRINFO)
 fi
 
-# Enable Berkeley DB support if requested (for AG_DbObject).
-if [ "${with_db4}" = "yes" ]; then
+# Enable Berkeley DB backend for AG_Db if available.
+if [ "${with_db4}" != "no" ]; then
 CHECK(db4, ${prefix_db4})
 if [ "${HAVE_DB4}" != "yes" ]; then
 if [ "${with_db4}" = "yes" ]; then
 echo "*"
-echo "* --with-db4 was requested, but Berkeley DB v4"
+echo "* --with-db4 was requested, but Berkeley DB"
 echo "* was not found."
 echo "*"
 exit 1
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-02-24T03:18:32</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1405">
    <title>Agar: r9091 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1405</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-02-23 22:17:50 -0500 (Thu, 23 Feb 2012)
New Revision: 9091

Added:
   trunk/core/db_bdb.c
   trunk/core/db_mysql.c
   trunk/core/text.c
   trunk/core/text.h
Removed:
   trunk/core/string.c
   trunk/core/string.h
Modified:
   trunk/core/AG_Threads.3
   trunk/core/AG_Variable.3
   trunk/core/Makefile
   trunk/core/core.c
   trunk/core/core.h
   trunk/core/core_pub.h
   trunk/core/db.c
   trunk/core/db.h
   trunk/core/variable.c
   trunk/core/variable.h
Log:
new AG_Db and AG_Text interfaces



Modified: trunk/core/AG_Threads.3
===================================================================
--- trunk/core/AG_Threads.32012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/AG_Threads.32012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -37,23 +37,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Sh DESCRIPTION
 On all platforms with threads support, Agar can be compiled with support for
 multithreading.
-Agar API calls, unless otherwise documented, then become safe to invoke from
-arbitrary threads within an application.
-Internally this is achieved using fined-grained locking devices.
-.Pp
-The Agar object system (see
-.Xr AG_Object 3 )
-provides built-in mechanisms to facilitate thread safety, such as per-object
-locks which remain held throughout the execution of event handlers.
+Agar API calls, unless otherwise documented, then become
+.Em free-threaded
+(safe to use from different threads without need for application-level
+synchronization).
 .Sh CONVENTIONS
-With respect to threads, the Agar documentation follows the convention that
-all functions are entirely safe to invoke from any thread, unless documented
-otherwise.
+The Agar API documentation follows the convention that all functions are
+free-threaded, unless mentioned otherwise.
 .Pp
-When multithreading is used, the return values of functions (except for error
-codes), should only be considered safe to use for as long as the related
-Agar objects are locked.
-For example, the following code is unsafe:
+Under some circumstances, application-level synchronization is required.
+The
+.Xr AG_Object 3
+simplifies this task by providing a per-object lock (which is implicitely
+acquired in some contexts, such as event handler execution).
+For instance, the following code accesses a VFS in an unsafe manner:
 .Bd -literal -offset indent
 AG_Object *myObject;
 myObject = AG_ObjectFind(myRoot, "/Foo");
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -83,6 +80,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Ft "void"
 .Fn AG_MutexInitRecursive "AG_Mutex *mutex"
 .Pp
+.Ft "int"
+.Fn AG_MutexTryInit "AG_Mutex *mutex"
+.Pp
+.Ft "int"
+.Fn AG_MutexTryInitRecursive "AG_Mutex *mutex"
+.Pp
 .Ft "void"
 .Fn AG_MutexDestroy "AG_Mutex *mutex"
 .Pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -99,11 +102,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 The
 .Fn AG_MutexInit
 function initializes a mutex structure.
-The
 .Fn AG_MutexInitRecursive
-variant initializes a mutex which allows multiple
+initializes a recursive mutex (a mutex with a reference count),
+which allows nested
 .Fn AG_MutexLock
-using a reference count.
+calls.
+If the mutex cannot be allocated, a fatal error is raised.
+The
+.Fn AG_MutexTryInit
+and
+.Fn AG_MutexTryInitRecursive
+variants return an error code on failure.
 .Pp
 .Fn AG_MutexDestroy
 frees all resources allocated for a mutex.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -114,18 +123,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 respectively acquire and release a mutex.
 .Pp
 .Fn AG_MutexTryLock
-tries to acquire a mutex without blocking and immediately returns 0 on success
-and -1 on failure.
-.Pp
-All of these functions except
+tries to acquire a mutex without blocking and immediately returns 0 on
+success and -1 on failure.
+Note that
 .Fn AG_MutexTryLock
-will raise a fatal condition if an error is encountered.
+does not set any error message with
+.Xr AG_SetError 3 .
 .Sh CONDITION VARIABLES
 .\" MANLINK(AG_Cond)
 .nr nS 1
 .Ft "void"
 .Fn AG_CondInit "AG_Cond *cv"
 .Pp
+.Ft "int"
+.Fn AG_CondTryInit "AG_Cond *cv"
+.Pp
 .Ft "void"
 .Fn AG_CondDestroy "AG_Cond *cv"
 .Pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -144,6 +156,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .nr nS 0
 .Fn AG_CondInit
 initializes a condition variable structure.
+If the condition variable cannot be allocated, a fatal error is raised.
+The
+.Fn AG_CondTryInit
+variant returns an error code on failure.
+.Pp
 .Fn AG_CondDestroy
 releases resources allocated for a condition variable.
 .Pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -166,9 +183,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Sh THREADS
 .\" MANLINK(AG_Thread)
 .nr nS 1
-.Ft int
+.Ft void
 .Fn AG_ThreadCreate "AG_Thread *th" "void *(*fn)(void *arg)" "void *arg"
 .Pp
+.Ft int
+.Fn AG_ThreadTryCreate "AG_Thread *th" "void *(*fn)(void *arg)" "void *arg"
+.Pp
 .Ft void
 .Fn AG_ThreadCancel "AG_Thread th"
 .Pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -194,6 +214,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 initializes the
 .Fa th
 structure and returns 0.
+On failure, a fatal error is raised.
+The
+.Fn AG_ThreadTryCreate
+variant returns an error if the thread could not be created.
 .Pp
 .Fn AG_ThreadCancel
 requests that the specified thread be cancelled.

Modified: trunk/core/AG_Variable.3
===================================================================
--- trunk/core/AG_Variable.32012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/AG_Variable.32012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,4 +1,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-.\" Copyright (c) 2009 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+.\" Copyright (c) 2009-2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -64,6 +64,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Ft "AG_Variable *"
 .Fn AG_GetVariableLocked "AG_Object *obj" "const char *name"
 .Pp
+.Ft "void"
+.Fn AG_LockVariable "AG_Variable *var"
+.Pp
+.Ft "void"
+.Fn AG_UnlockVariable "AG_Variable *var"
+.Pp
 .Ft "AG_Variable *"
 .Fn AG_GetVariableVFS "AG_Object *obj" "const char *name" 
 .Pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -119,6 +125,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Fn AG_UnlockVariable
 when done accessing the data.
 .Pp
+.Fn AG_LockVariable
+and
+.Fn AG_UnlockVariable
+acquire and release any locking device associated with the
+specified variable.
+.Pp
 .Fn AG_GetVariableVFS
 searches an
 .Xr AG_Object 3
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -429,6 +441,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Ft "char *"
 .Fn AG_GetStringDup "AG_Object *obj" "const char *name"
 .Pp
+.Ft "char *"
+.Fn AG_GetStringP "AG_Object *obj" "const char *name"
+.Pp
 .Ft "void"
 .Fn AG_InitString "AG_Variable *var" "const char *s"
 .Pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -469,8 +484,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Fn AG_BindConstStringMp "AG_Object *obj" "const char *name" "const char **s" "AG_Mutex *lock"
 .Pp
 .nr nS 0
-These functions provide an interface to string types.
-To handle strings properly, their form differs from that of primitive types.
+These functions provide an interface to variable-length and fixed-length
+C strings.
+A string variable can reference an internal, statically-defined string (see
+.Fn AG_SetString ) ,
+or an external fixed-size buffer containing a valid C string (see
+.Fn AG_BindString ) .
+It is also possible to have a string variable defined by a function (see
+.Fn AG_BindStringFn ) .
 .Pp
 .Fn AG_GetString
 returns the contents of a string variable.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -486,6 +507,24 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 returns a newly-allocated copy of the string variable.
 If the string cannot be allocated, NULL is returned.
 .Pp
+The
+.Fn AG_GetStringP
+function returns a direct pointer to the buffer containing the string.
+If the given variable is function-defined (i.e., it was set by
+.Fn AG_BindStringFn ) ,
+the value generated by the last
+.Fn AG_EvalVariable
+operation is returned.
+Note that
+.Fn AG_GetStringP
+is NOT free-threaded: safely accessing the string requires that the
+application calls
+.Fn AG_LockVariable .
+As an exception to this rule, static strings (i.e., strings set by
+.Fn AG_SetString )
+may be considered safe to access without locking, as long as the
+string variable's parent object is locked.
+.Pp
 .Fn AG_InitString
 initializes a
 .Nm
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -504,22 +543,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Fa len .
 .Pp
 .Fn AG_SetString
-creates or modifies a named string variable with the value
+sets the named string variable to the given string
 .Fa s .
+The argument may be set to NULL (in which case further
+.Fn AG_GetString
+calls will return NULL).
+.Pp
 The
 .Fn AG_SetStringNODUP
-variant reuses the
+variant is NOT free-threaded: it uses the 
 .Fa s
-pointer without copying the string, assuming the pointer will
+pointer directly without copying the string, assuming the pointer will
 remain valid for as long as the variable exists.
+.Pp
+The
 .Fn AG_PrtString
-is a variant of
-.Fn AG_SetString
-which accepts a printf-style format string.
-If any of those three functions are invoked on an existing variable previously
-created with
-.Fn AG_BindString ,
-the string is copied onto the existing string buffer.
+variant sets a string variable from a format string argument.
 .Pp
 The
 .Fn AG_SetStringFixed
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -528,9 +567,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Fa s ,
 of size
 .Fa len .
-If invoked on an existing variable previously created with
-.Fn AG_BindString ,
-the buffer pointer is simply overwritten.
 .Pp
 .Fn AG_BindString
 creates or modifies a variable referencing a fixed-size string buffer
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -541,13 +577,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Fn AG_BindStringFn
 variant ties the variable to a function
 .Fa fn .
-.Pp
-The functions
-.Fn AG_SetConstString ,
-.Fn AG_BindConstString
-and
-.Fn AG_BindConstStringMp
-follow the standard form for primitive type variables.
 .Sh GENERIC POINTERS
 .nr nS 1
 .Ft "void *"

Modified: trunk/core/Makefile
===================================================================
--- trunk/core/Makefile2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/Makefile2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,7 +16,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 net_client.c net_command.c net_fgetln.c net_server.c \
 dir.c md5.c sha1.c rmd160.c file.c string_compat.c dso.c tree.c \
 time.c time_dummy.c time_gettimeofday.c time_win32.c time_condwait.c \
-db.c dbobject.c tbl.c getopt.c exec.c string.c
+db.c db_bdb.c db_mysql.c tbl.c getopt.c exec.c text.c
 
 MAN3=AG_Intro.3 AG_Core.3 AG_Event.3 AG_Object.3 AG_Prop.3 AG_Timeout..3 \
 AG_Config.3 AG_Version.3 AG_DataSource.3 AG_Error.3 AG_Threads.3 \

Modified: trunk/core/core.c
===================================================================
--- trunk/core/core.c2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/core.c2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -37,6 +37,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;config/have_select.h&amp;gt;
 #include &amp;lt;config/have_cygwin.h&amp;gt;
 #include &amp;lt;config/have_clock_gettime.h&amp;gt;
+#include &amp;lt;config/have_db4.h&amp;gt;
 
 #ifdef AG_THREADS
 #include &amp;lt;config/have_pthreads_xopen.h&amp;gt;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -104,8 +105,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 AG_InitClassTbl();
 AG_RegisterClass(&amp;amp;agConfigClass);
-AG_RegisterClass(&amp;amp;agDbObjectClass);
 AG_RegisterClass(&amp;amp;agDbClass);
+#ifdef HAVE_DB4
+AG_RegisterClass(&amp;amp;agDbHashClass);
+AG_RegisterClass(&amp;amp;agDbBtreeClass);
+#endif
 
 #if defined(HAVE_GETTIMEOFDAY) &amp;amp;&amp;amp; !defined(HAVE_CYGWIN)
 # if defined(AG_THREADS) &amp;amp;&amp;amp; defined(HAVE_CLOCK_GETTIME)

Modified: trunk/core/core.h
===================================================================
--- trunk/core/core.h2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/core.h2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -90,9 +90,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;core/dso.h&amp;gt;
 #include &amp;lt;core/time.h&amp;gt;
 #include &amp;lt;core/db.h&amp;gt;
-#include &amp;lt;core/dbobject.h&amp;gt;
 #include &amp;lt;core/exec.h&amp;gt;
-#include &amp;lt;core/string.h&amp;gt;
+#include &amp;lt;core/text.h&amp;gt;
 
 #endif /* !_AGAR_CORE_CORE_H_ */
 #endif /* _AGAR_INTERNAL */

Modified: trunk/core/core_pub.h
===================================================================
--- trunk/core/core_pub.h2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/core_pub.h2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -32,10 +32,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;agar/core/dso.h&amp;gt;
 #include &amp;lt;agar/core/time.h&amp;gt;
 #include &amp;lt;agar/core/db.h&amp;gt;
-#include &amp;lt;agar/core/dbobject.h&amp;gt;
 #include &amp;lt;agar/core/getopt.h&amp;gt;
 #include &amp;lt;agar/core/exec.h&amp;gt;
-#include &amp;lt;agar/core/string.h&amp;gt;
+#include &amp;lt;agar/core/text.h&amp;gt;
 
 #include &amp;lt;agar/core/core_close.h&amp;gt;
 #endif

Modified: trunk/core/db.c
===================================================================
--- trunk/core/db.c2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/db.c2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,5 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /*
- * Copyright (c) 2009 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+ * Copyright (c) 2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -23,297 +23,117 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/*
- * Simple key/value database class.
- */
-
 #include &amp;lt;config/have_db4.h&amp;gt;
 #include &amp;lt;core/core.h&amp;gt;
 
-#ifdef HAVE_DB4
-#include &amp;lt;db4/db.h&amp;gt;
-#endif
-
-/* Create a new database. */
+/* Create a new database handle for the given database backend. */
 AG_Db *
-AG_DbNew(enum ag_db_type type)
+AG_DbNew(const char *backend)
 {
 AG_Db *db;
+AG_DbClass *dbc = NULL;
 
-if ((db = TryMalloc(sizeof(AG_Db))) == NULL) {
-return (NULL);
-}
-AG_ObjectInit(db, &amp;amp;agDbClass);
-db-&amp;gt;type = type;
-return (db);
-}
-
-/* Create a new DB4 database. */
-AG_Db *
-AG_DbNewDB4(const char *path, enum ag_db4_type db4_type, Uint32 db4_flags)
-{
 #ifdef HAVE_DB4
-AG_Db *db;
-int rv;
-DB *dbp;
-
-if ((db = AG_DbNew(AG_DB_DB4)) == NULL) {
-return (NULL);
+/* XXX */
+if (strcmp(backend, "hash")) {
+dbc = &amp;amp;agDbHashClass;
+} else if (strcmp(backend, "btree")) {
+dbc = &amp;amp;agDbBtreeClass;
 }
-if ((rv = db_create(&amp;amp;dbp, NULL, 0)) != 0) {
-AG_SetError("db_create: %s", db_strerror(rv));
-AG_ObjectDestroy(db);
+#endif
+if (dbc == NULL) {
+AG_SetError("No such database backend: %s", backend);
 return (NULL);
 }
-db-&amp;gt;db4 = (void *)dbp;
-rv = ((DB *)db-&amp;gt;db4)-&amp;gt;open((DB *)db-&amp;gt;db4, NULL, path,
-    (DBTYPE)db4_type, db4_flags, 0);
-if (rv != 0) {
-AG_SetError("%s: %s", path, db_strerror(rv));
+if ((db = TryMalloc(sizeof(AG_Db))) == NULL) {
 return (NULL);
 }
+AG_ObjectInit(db, dbc);
 return (db);
-#else
-AG_SetError("Berkeley DB4 support was not compiled in");
-return (NULL);
-#endif /* HAVE_DB4 */
 }
 
-/* Return the list of keys (as strings) in a given database. */
-AG_List *
-AG_DbListKeys(AG_Db *db)
-{
-AG_List *L;
-
-if ((L = AG_ListNew()) == NULL)
-return (NULL);
-
-switch (db-&amp;gt;type) {
-#ifdef HAVE_DB4
-case AG_DB_DB4: {
-DBC *c;
-DBT key, data;
-int rv;
-
-((DB *)db-&amp;gt;db4)-&amp;gt;cursor((DB *)db-&amp;gt;db4, NULL, &amp;amp;c, 0);
-memset(&amp;amp;key, 0, sizeof(DBT));
-memset(&amp;amp;data, 0, sizeof(DBT));
-while ((rv = c-&amp;gt;c_get(c, &amp;amp;key, &amp;amp;data, DB_NEXT)) == 0) {
-AG_Variable Vnew;
-AG_InitString(&amp;amp;Vnew, key.data);
-AG_ListAppend(L, &amp;amp;Vnew);
-}
-if (rv != DB_NOTFOUND) {
-AG_SetError("Retrieving db keys: %s", db_strerror(rv));
-AG_ListDestroy(L);
-return (NULL);
-}
-c-&amp;gt;c_close(c);
-break;
-}
-#endif
-default:
-break;
-}
-return (L);
-}
-
-/* Returns whether a key exists (string). */
+/* Open a database. */
 int
-AG_DbExists(AG_Db *db, const char *s)
+AG_DbOpen(AG_Db *db, const char *path, Uint flags)
 {
-return AG_DbExistsDK(db, (void *)s, strlen(s)+1);
-}
+AG_DbClass *dbc = AGDB_CLASS(db);
+int rv;
 
-/* Returns whether a key exists (data). */
-int
-AG_DbExistsDK(AG_Db *db, void *keyData, size_t keySize)
-{
-switch (db-&amp;gt;type) {
-#ifdef HAVE_DB4
-case AG_DB_DB4: {
-DBT key, data;
-int rv;
-
-memset(&amp;amp;key, 0, sizeof(DBT));
-memset(&amp;amp;data, 0, sizeof(DBT));
-key.data = keyData;
-key.size = keySize;
-if ((rv = ((DB *)db-&amp;gt;db4)-&amp;gt;get((DB *)db-&amp;gt;db4, NULL,
-    &amp;amp;key, &amp;amp;data, 0)) != DB_NOTFOUND) {
-return (1);
-}
-break;
+AG_ObjectLock(db);
+if (db-&amp;gt;flags &amp;amp; AG_DB_OPEN) {
+AG_SetError(_("Database is already open"));
+goto fail;
 }
-#endif
-default:
-break;
+rv = (dbc-&amp;gt;open != NULL) ? dbc-&amp;gt;open(db, path, flags) : 0;
+if (rv != 0) {
+goto fail;
 }
+db-&amp;gt;flags |= AG_DB_OPEN;
+AG_ObjectUnlock(db);
 return (0);
+fail:
+AG_ObjectUnlock(db);
+return (-1);
 }
 
-/* Lookup a database entry by key (string). */
-int
-AG_DbLookup(AG_Db *db, AG_DbEntry *dbe, const char *s)
+/* Close a database. */
+void
+AG_DbClose(AG_Db *db)
 {
-return AG_DbLookupDK(db, dbe, (void *)s, strlen(s)+1);
-}
-
-/* Lookup a database entry by key (data). */
-int
-AG_DbLookupDK(AG_Db *db, AG_DbEntry *dbe, void *keyData, size_t keySize)
-{
-dbe-&amp;gt;db = db;
-
-switch (db-&amp;gt;type) {
-#ifdef HAVE_DB4
-case AG_DB_DB4: {
-DBT key, data;
-int rv;
-
-memset(&amp;amp;key, 0, sizeof(DBT));
-memset(&amp;amp;data, 0, sizeof(DBT));
-key.data = keyData;
-key.size = keySize;
-if ((rv = ((DB *)db-&amp;gt;db4)-&amp;gt;get((DB *)db-&amp;gt;db4, NULL,
-    &amp;amp;key, &amp;amp;data, 0)) != 0) {
-AG_SetError("DB Lookup: %s", db_strerror(rv));
-return (-1);
+AG_DbClass *dbc = AGDB_CLASS(db);
+
+AG_ObjectLock(db);
+if (db-&amp;gt;flags &amp;amp; AG_DB_OPEN) {
+if (dbc-&amp;gt;close != NULL) {
+dbc-&amp;gt;close(db);
 }
-dbe-&amp;gt;key = (void *)key.data;
-dbe-&amp;gt;keySize = (size_t)key.size;
-dbe-&amp;gt;data = (void *)data.data;
-dbe-&amp;gt;dataSize = (size_t)data.size;
-break;
+db-&amp;gt;flags &amp;amp;= ~(AG_DB_OPEN);
 }
-#endif
-default:
-AG_SetError("Unsupported operation");
-return (-1);
-}
-return (0);
+AG_ObjectUnlock(db);
 }
 
-/* Put an entry onto the database, overwrite if exists. */
+/* Synchronize a database. */
 int
-AG_DbPut(AG_Db *db, AG_DbEntry *dbe)
-{
-switch (db-&amp;gt;type) {
-#ifdef HAVE_DB4
-case AG_DB_DB4: {
-DBT key, data;
-int rv;
-
-memset(&amp;amp;key, 0, sizeof(DBT));
-key.data = dbe-&amp;gt;key;
-key.size = dbe-&amp;gt;keySize;
-memset(&amp;amp;data, 0, sizeof(DBT));
-data.data = dbe-&amp;gt;data;
-data.size = dbe-&amp;gt;dataSize;
-if ((rv = ((DB *)db-&amp;gt;db4)-&amp;gt;put((DB *)db-&amp;gt;db4, NULL,
-    &amp;amp;key, &amp;amp;data, 0)) != 0) {
-AG_SetError("DB Put: %s", db_strerror(rv));
-return (-1);
-}
-break;
-}
-#endif
-default:
-AG_SetError("Unsupported operation");
-return (-1);
-}
-return (0);
-}
-
-/* Sync the database */
-int
 AG_DbSync(AG_Db *db)
 {
-switch (db-&amp;gt;type) {
-#ifdef HAVE_DB4
-case AG_DB_DB4: {
-int rv;
-if ((rv = ((DB *)db-&amp;gt;db4)-&amp;gt;sync((DB *)db-&amp;gt;db4, 0)) != 0) {
-AG_SetError("DB Sync: %s", db_strerror(rv));
-return (-1);
-}
-break;
-}
-#endif
-default:
-break;
-}
-return (0);
+AG_DbClass *dbc = AGDB_CLASS(db);
+int rv;
+
+AG_ObjectLock(db);
+rv = (dbc-&amp;gt;sync != NULL) ? dbc-&amp;gt;sync(db) : 0;
+AG_ObjectUnlock(db);
+return (rv);
 }
 
-/* Remove an entry from the database by key (string). */
-int
-AG_DbDelete(AG_Db *db, const char *key)
-{
-return AG_DbDeleteDK(db, (void *)key, strlen(key)+1);
-}
-
-/* Remove an entry from the database by key (data). */
-int
-AG_DbDeleteDK(AG_Db *db, void *keyData, size_t keySize)
-{
-switch (db-&amp;gt;type) {
-#ifdef HAVE_DB4
-case AG_DB_DB4: {
-DBT key, data;
-int rv;
-
-memset(&amp;amp;key, 0, sizeof(DBT));
-memset(&amp;amp;data, 0, sizeof(DBT));
-key.data = keyData;
-key.size = keySize;
-if ((rv = ((DB *)db-&amp;gt;db4)-&amp;gt;get((DB *)db-&amp;gt;db4, NULL,
-    &amp;amp;key, &amp;amp;data, 0)) == DB_NOTFOUND) {
-AG_SetError("DB Delete: No such entry");
-return (-1);
-}
-if ((rv = ((DB *)db-&amp;gt;db4)-&amp;gt;del((DB *)db-&amp;gt;db4, NULL, &amp;amp;key, 0))
-    != 0) {
-AG_SetError("DB Delete: %s", db_strerror(rv));
-return (-1);
-}
-break;
-}
-#endif /* HAVE_DB4 */
-default:
-AG_SetError("Unsupported operation");
-return (-1);
-}
-return (0);
-}
-
 static void
 Init(void *obj)
 {
 AG_Db *db = obj;
-db-&amp;gt;type = AG_DB_DUMMY;
-}
 
-static void
-Destroy(void *obj)
-{
-#ifdef HAVE_DB4
-AG_Db *db = obj;
-int rv;
-
-if ((rv = ((DB *)db-&amp;gt;db4)-&amp;gt;close((DB *)db-&amp;gt;db4, 0)) != 0)
-AG_FatalError("Closing database: %s", db_strerror(rv));
-#endif
+db-&amp;gt;flags = 0;
 }
 
-AG_ObjectClass agDbClass = {
-"AG_Db",
-sizeof(AG_Db),
-{ 0, 0 },
-Init,
-NULL,/* reinit */
-Destroy,
-NULL,/* load */
-NULL,/* save */
-NULL/* edit */
+AG_DbClass agDbClass = {
+{
+"Agar(Db)",
+sizeof(AG_Db),
+{ 0,0 },
+Init,
+NULL,/* free */
+NULL,/* destroy */
+NULL,/* load */
+NULL,/* save */
+NULL/* edit */
+},
+"dummy",
+N_("Dummy database backend"),
+AG_DB_KEY_DATA,/* Key is variable data */
+AG_DB_REC_VARIABLE,/* Variable-sized records */
+NULL,/* open */
+NULL,/* close */
+NULL,/* sync */
+NULL,/* exists */
+NULL,/* get */
+NULL,/* put */
+NULL/* del */
 };

Modified: trunk/core/db.h
===================================================================
--- trunk/core/db.h2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/db.h2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -4,61 +4,134 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define _AGAR_CORE_DB_H_
 #include &amp;lt;agar/core/begin.h&amp;gt;
 
+struct ag_db;
+
 /* Type of database */
 enum ag_db_type {
-AG_DB_DUMMY,/* No-op */
-AG_DB_DB4,/* Berkeley DB v4 */
+AG_DB_DUMMY,/* No-op */
+AG_DB_BTREE,/* BDB: Sorted, balanced tree structure */
+AG_DB_HASH,/* BDB: Extended Linear Hashing */
 AG_DB_LAST
 };
 
-/* DB4 database subtype */
-enum ag_db4_type {
-AG_DB4_BTREE= 1,
-AG_DB4_HASH= 2,
-AG_DB4_RECNO= 3,
-AG_DB4_QUEUE= 4,
-AG_DB4_UNKNOWN= 5
-};
+typedef struct ag_db_entry {
+struct ag_db *db;/* Back pointer to Db */
+void *key, *data;
+size_t keySize, dataSize;
+} AG_DbEntry;
 
-/* DB4 database open flags */
-#defineAG_DB4_AUTO_COMMIT0x2000000
-#defineAG_DB4_CREATE0x0000001
-#defineAG_DB4_EXCL0x0004000
-#defineAG_DB4_MULTIVERSION0x0000008
-#defineAG_DB4_NOMMAP0x0000010
-#defineAG_DB4_RDONLY0x0000020
-#defineAG_DB4_THREAD0x0000080
-#defineAG_DB4_TRUNCATE0x0000100
-#defineAG_DB4_READ_UNCOMMITTED0x8000000
+typedef void (*AG_DbIterateFn)(void *db, void *key, size_t keySize,
+                               void *data, size_t dataSize);
 
+typedef struct ag_db_class {
+struct ag_object_class _inherit;
+const char *name;/* Database method name */
+const char *descr;/* Short description */
+enum ag_db_key_mode {
+AG_DB_KEY_DATA,/* Variable-length data */
+AG_DB_KEY_NUMBER,/* Logical record number */
+AG_DB_KEY_STRING/* Legal C string */
+} keyMode;
+enum ag_db_record_mode {
+AG_DB_REC_VARIABLE,/* Variable-length records */
+AG_DB_REC_FIXED/* Fixed-length records */
+} recMode;
+int  (*open)(void *, const char *, Uint);
+void (*close)(void *);
+int  (*sync)(void *);
+int  (*exists)(void *, AG_DbEntry *);
+int  (*get)(void *, AG_DbEntry *);
+int  (*put)(void *, AG_DbEntry *);
+int  (*del)(void *, AG_DbEntry *);
+int  (*iterate)(void *, AG_DbIterateFn);
+} AG_DbClass;
+
+#define AGDB_CLASS(db) ((AG_DbClass *)AGOBJECT(db)-&amp;gt;cls)
+
 typedef struct ag_db {
-struct ag_object obj;
-enum ag_db_type type;
-void *db4;/* Pointer to DB object */
+struct ag_object _inherit;
+Uint flags;
+#define AG_DB_OPEN0x01/* Database is open */
+#define AG_DB_READONLY0x02/* Open in read-only mode */
 } AG_Db;
 
-typedef struct ag_db_entry {
-AG_Db *db;/* Back pointer to Db */
-void *key, *data;
-size_t keySize, dataSize;
-} AG_DbEntry;
-
 #define AGDB(p) ((AG_Db *)(p))
 
 __BEGIN_DECLS
-extern AG_ObjectClass agDbClass;
+extern AG_DbClass agDbClass;
+extern AG_DbClass agDbHashClass;
+extern AG_DbClass agDbBtreeClass;
+extern AG_DbClass agDbMySQLClass;
 
-AG_Db       *AG_DbNew(enum ag_db_type);
-AG_Db       *AG_DbNewDB4(const char *, enum ag_db4_type, Uint32);
-AG_List     *AG_DbListKeys(AG_Db *);
-int          AG_DbExists(AG_Db *, const char *);
-int          AG_DbExistsDK(AG_Db *, void *, size_t);
-int          AG_DbLookup(AG_Db *, AG_DbEntry *, const char *);
-int          AG_DbLookupDK(AG_Db *, AG_DbEntry *, void *, size_t);
-int          AG_DbDelete(AG_Db *, const char *);
-int          AG_DbDeleteDK(AG_Db *, void *, size_t);
-int          AG_DbPut(AG_Db *, AG_DbEntry *);
+AG_Db       *AG_DbNew(const char *);
+int          AG_DbOpen(AG_Db *, const char *, Uint);
+void         AG_DbClose(AG_Db *);
 int          AG_DbSync(AG_Db *);
+
+/* Test for existence of a key. */
+static __inline__ int
+AG_DbExists(AG_Db *db, AG_DbEntry *dbe)
+{
+AG_DbClass *dbc = AGDB_CLASS(db);
+int rv;
+
+AG_ObjectLock(db);
+rv = dbc-&amp;gt;exists(db, dbe);
+AG_ObjectUnlock(db);
+return (rv);
+}
+
+/* Get operation (BDB-style argument). */
+static __inline__ int
+AG_DbGet(AG_Db *db, AG_DbEntry *dbe)
+{
+AG_DbClass *dbc = AGDB_CLASS(db);
+int rv;
+
+AG_ObjectLock(db);
+rv = dbc-&amp;gt;get(db, dbe);
+AG_ObjectUnlock(db);
+return (rv);
+}
+
+/* Put operation (BDB-style argument). */
+static __inline__ int
+AG_DbPut(AG_Db *db, AG_DbEntry *dbe)
+{
+AG_DbClass *dbc = AGDB_CLASS(db);
+int rv;
+
+AG_ObjectLock(db);
+rv = dbc-&amp;gt;put(db, dbe);
+AG_ObjectUnlock(db);
+return (rv);
+}
+
+/* Delete operation (BDB-style argument). */
+static __inline__ int
+AG_DbDel(AG_Db *db, AG_DbEntry *dbe)
+{
+AG_DbClass *dbc = AGDB_CLASS(db);
+int rv;
+
+AG_ObjectLock(db);
+rv = dbc-&amp;gt;del(db, dbe);
+AG_ObjectUnlock(db);
+return (rv);
+}
+
+/* Iterate over all entries. */
+static __inline__ int
+AG_DbIterate(AG_Db *db, AG_DbIterateFn fn)
+{
+AG_DbClass *dbc = AGDB_CLASS(db);
+int rv;
+
+AG_ObjectLock(db);
+rv = dbc-&amp;gt;iterate(db, fn);
+AG_ObjectUnlock(db);
+return (rv);
+}
 __END_DECLS
 
 #include &amp;lt;agar/core/close.h&amp;gt;

Added: trunk/core/db_bdb.c
===================================================================
--- trunk/core/db_bdb.c                        (rev 0)
+++ trunk/core/db_bdb.c2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,296 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * Copyright (c) 2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Berkeley DB database access.
+ */
+
+#include &amp;lt;config/have_db4.h&amp;gt;
+#ifdef HAVE_DB4
+
+#include &amp;lt;core/core.h&amp;gt;
+#include &amp;lt;db.h&amp;gt;
+
+typedef struct ag_db_hash_bt {
+struct ag_db _inherit;
+DB *pDB;
+} AG_DbHashBT;
+
+static const struct {
+const char *name;
+Uint32 mask;
+} agBDBOptions[] = {
+{ "db-create",DB_CREATE },
+{ "db-create-excl",DB_EXCL },
+{ "db-auto-commit",DB_AUTO_COMMIT },
+{ "db-threaded",DB_THREAD },
+{ "db-truncate",DB_TRUNCATE },
+#ifdef DB_MULTIVERSION
+{ "db-multiversion",DB_MULTIVERSION },
+#endif
+#ifdef DB_NOMMAP
+{ "db-no-mmap",DB_NOMMAP },
+#endif
+#ifdef DB_READ_UNCOMMITTED
+{ "db-read-uncommitted",DB_READ_UNCOMMITTED },
+#endif
+};
+static const int agBDBOptionCount = sizeof(agBDBOptions)/sizeof(agBDBOptions[0]);
+
+static void
+Init(void *obj)
+{
+AG_DbHashBT *hbt = obj;
+int i;
+
+for (i = 0; i &amp;lt; ag; i++)
+AG_SetInt(hbt, agBDBOptions[i].name, 0);
+}
+
+static int
+Open(void *obj, const char *path, Uint flags)
+{
+AG_DbHashBT *hbt = obj;
+Uint32 dbFlags = 0;
+int i, rv;
+DBTYPE dbtype;
+
+if (strcmp(AGDB_OPS(hbt)-&amp;gt;name, "hash") == 0) {
+dbtype = DB_HASH;
+} else {
+dbtype = DB_BTREE;
+}
+if ((rv = db_create(&amp;amp;hbt-&amp;gt;pDB, NULL, 0)) != 0) {
+AG_SetError("db_create: %s", db_strerror(rv));
+return (-1);
+}
+for (i = 0; i &amp;lt; agBDBOptionsCount; i++) {
+if (AG_GetInt(hbt, agBDBOptions[i].name))
+dbFlags |= agBDBOptions[i].mask;
+}
+if (flags &amp;amp; AG_DB_READONLY) {
+dbFlags |= DB_RDONLY;
+}
+rv = hbt-&amp;gt;pDB-&amp;gt;open(hbt-&amp;gt;pDB, NULL, path, dbtype, dbFlags, 0);
+if (rv != 0) {
+AG_SetError("db_open %s: %s", path, db_strerror(rv));
+return (-1);
+}
+return (0);
+}
+
+static void
+Close(void *obj)
+{
+AG_DbHashBT *hbt = obj;
+int rv;
+
+if ((rv = hbt-&amp;gt;pDB-&amp;gt;close(hbt-&amp;gt;pDB, 0)) != 0)
+AG_Verbose("db_close: %s; ignoring", db_strerror(rv));
+}
+
+static int
+Sync(void *obj)
+{
+AG_DbHashBT *hbt = obj;
+int rv;
+
+if ((rv = hbt-&amp;gt;pDB-&amp;gt;sync(hbt-&amp;gt;pDB, 0)) != 0) {
+AG_SetError("db_sync: %s", db_strerror(rv));
+return (-1);
+}
+return (0);
+}
+
+static int
+Exists(void *obj, AG_DbEntry *dbe)
+{
+AG_DbHashBT *hbt = obj;
+DBT key;
+int rv;
+
+memset(&amp;amp;key, 0, sizeof(DBT));
+key.data = dbe-&amp;gt;keyData;
+key.size = dbe-&amp;gt;keySize;
+if ((rv = hbt-&amp;gt;pDB-&amp;gt;exists(hbt-&amp;gt;pDB, NULL, &amp;amp;key, 0)) != DB_NOTFOUND) {
+return (1);
+}
+return (0);
+}
+
+static int
+Get(void *obj, AG_DbEntry *dbe)
+{
+AG_DbHashBT *hbt = obj;
+DBT key, data;
+int rv;
+
+memset(&amp;amp;key, 0, sizeof(DBT));
+memset(&amp;amp;data, 0, sizeof(DBT));
+key.data = keyData;
+key.size = keySize;
+if ((rv = hbt-&amp;gt;pDB-&amp;gt;get(hbt-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) != 0) {
+AG_SetError("db_get: %s", db_strerror(rv));
+return (-1);
+}
+dbe-&amp;gt;key = (void *)key.data;
+dbe-&amp;gt;keySize = (size_t)key.size;
+dbe-&amp;gt;data = (void *)data.data;
+dbe-&amp;gt;dataSize = (size_t)data.size;
+return (0);
+}
+
+static int
+Put(void *obj, AG_DbEntry *dbe)
+{
+AG_DbHashBT *hbt = obj;
+DBT key, data;
+int rv;
+
+memset(&amp;amp;key, 0, sizeof(DBT));
+key.data = dbe-&amp;gt;key;
+key.size = dbe-&amp;gt;keySize;
+memset(&amp;amp;data, 0, sizeof(DBT));
+data.data = dbe-&amp;gt;data;
+data.size = dbe-&amp;gt;dataSize;
+if ((rv = hbt-&amp;gt;pDB-&amp;gt;put(hbt-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) != 0) {
+AG_SetError("db_put: %s", db_strerror(rv));
+return (-1);
+}
+return (0);
+}
+
+static int
+Del(void *obj, AG_DbEntry *dbe)
+{
+AG_DbHashBT *hbt = obj;
+DBT key, data;
+int rv;
+
+memset(&amp;amp;key, 0, sizeof(DBT));
+memset(&amp;amp;data, 0, sizeof(DBT));
+key.data = keyData;
+key.size = keySize;
+#if 0
+if ((rv = hbt-&amp;gt;pDB-&amp;gt;get(hbt-&amp;gt;pDB, NULL, &amp;amp;key, &amp;amp;data, 0)) == DB_NOTFOUND) {
+AG_SetError("db_del: No such entry");
+return (-1);
+}
+#endif
+if ((rv = hbt-&amp;gt;pDB-&amp;gt;del(hbt-&amp;gt;pDB, NULL, &amp;amp;key, 0)) != 0) {
+AG_SetError("DB Delete: %s", db_strerror(rv));
+return (-1);
+}
+return (0);
+}
+
+static int
+Iterate(void *obj, AG_DbIterateFn fn)
+{
+AG_DbHashBT *hbt = obj;
+AG_List *L;
+DBC *c;
+DBT key, data;
+int rv;
+
+hbt-&amp;gt;pDB-&amp;gt;cursor(hbt-&amp;gt;pDB, NULL, &amp;amp;c, 0);
+memset(&amp;amp;key, 0, sizeof(DBT));
+memset(&amp;amp;data, 0, sizeof(DBT));
+while ((rv = c-&amp;gt;c_get(c, &amp;amp;key, &amp;amp;data, DB_NEXT)) == 0) {
+AG_DbEntry dbe;
+
+dbe.db = db;
+dbe.key = key.data;
+dbe.keySize key.size;
+dbe.data = data.data;
+dbe.dataSize = data.size;
+
+if (fn(&amp;amp;dbe) == -1) {
+c-&amp;gt;c_close(c);
+return (-1);
+}
+}
+c-&amp;gt;c_close(c);
+
+if (rv != DB_NOTFOUND) {
+AG_SetError("c_get: %s", db_strerror(rv));
+return (-1);
+} else {
+return (0);
+}
+}
+
+AG_DbClass agDbHashClass = {
+{
+"Agar(Db:DbHash)",
+sizeof(AG_DbHashBT),
+{ 0,0 },
+Init,
+NULL,/* free */
+NULL,/* destroy */
+NULL,/* load */
+NULL,/* save */
+NULL/* edit */
+},
+"hash",
+N_("Extended Linear Hashing"),
+AG_DB_KEY_DATA,/* Key is variable data */
+AG_DB_REC_VARIABLE,/* Variable-sized records */
+Open,
+Close
+Sync,
+Exists,
+Get,
+Put,
+Del,
+Iterate
+};
+AG_DbClass agDbBtreeClass = {
+{
+"Agar(Db:DbHash)",
+sizeof(AG_DbHashBT),
+{ 0,0 },
+Init,
+NULL,/* free */
+NULL,/* destroy */
+NULL,/* load */
+NULL,/* save */
+NULL/* edit */
+},
+"btree",
+N_("Sorted, Balanced Tree Structure"),
+AG_DB_KEY_DATA,/* Key is variable data */
+AG_DB_REC_VARIABLE,/* Variable-sized records */
+Open,
+Close
+Sync,
+Exists,
+Get,
+Put,
+Del,
+Iterate
+};
+
+#endif /* HAVE_DB4 */

Added: trunk/core/db_mysql.c
===================================================================
--- trunk/core/db_mysql.c                        (rev 0)
+++ trunk/core/db_mysql.c2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,213 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * Copyright (c) 2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MySQL database access.
+ */
+
+#include &amp;lt;config/have_mysql.h&amp;gt;
+#ifdef HAVE_MYSQL
+
+#include &amp;lt;core/core.h&amp;gt;
+#include &amp;lt;db.h&amp;gt;
+#include &amp;lt;ctype.h&amp;gt;
+
+typedef struct ag_db_mysql {
+struct ag_db _inherit;
+MYSQL *my;
+} AG_DbMySQL;
+
+static void
+Init(void *obj)
+{
+AG_DbMySQL *db = obj;
+int i;
+
+AG_SetString(db, "host",NULL);
+AG_SetInt(db,    "port",0);
+AG_SetString(db, "database",NULL);
+AG_SetString(db, "user",NULL);
+AG_SetString(db, "password",NULL);
+AG_SetString(db, "unix-socket",NULL);
+AG_SetInt(db,    "compress",0);
+AG_SetInt(db,    "local-files",-1);
+AG_SetInt(db,    "ssl",-1);
+AG_SetInt(db,    "ssl-verify-cert",-1);
+AG_SetInt(db,    "secure-auth",-1);
+AG_SetString(db, "cnf-file",NULL);
+AG_SetString(db, "cnf-group",NULL);
+AG_SetString(db, "protocol","default");
+AG_SetUint(db,   "read-timeout",0);
+AG_SetInt(db,    "write-timeout",-1);
+AG_SetInt(db,    "reconnect",1);
+AG_SetString(db, "charset",NULL);
+AG_SetString(db, "charset-dir",NULL);
+
+AG_SetString(db, "init-cmd", NULL);
+AG_SetString(db, "get-cmd", "SELECT my_field FROM my_table "
+                                    "WHERE my_field = '%s'");
+AG_SetString(db, "put-cmd", "INSERT INTO my_table VALUES('%s')");
+}
+
+static int
+Open(void *obj, const char *path, Uint flags)
+{
+char dbName[128], host[128], user[128], pass[128];
+AG_DbMySQL *db = obj;
+MYSQL *my;
+unsigned long myFlags = CLIENT_REMEMBER_OPTIONS;
+char *s;
+Uint i;
+my_bool b = 1;
+
+if ((my = mysql_init(NULL)) == NULL) {
+AG_SetError("mysql_init failed");
+return (NULL);
+}
+if (path != NULL) {
+Strlcpy(dbName, path, sizeof(dbName));
+} else {
+AG_GetString(db, "database", dbName, sizeof(dbName));
+}
+if (AG_GetInt(db,"compress") == 1){ myFlags |= CLIENT_COMPRESS; }
+if (AG_GetInt(db,"local-files") == 1){ myFlags |= CLIENT_LOCAL_FILES; }
+if (AG_GetInt(db,"ssl") == 1){ myFlags |= CLIENT_SSL; }
+
+if (AG_GetUint(db,"ssl-verify-cert") == 1) { mysql_options(my, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &amp;amp;b); }
+if (AG_GetUint(db,"secure-auth") == 1) { mysql_options(my, MYSQL_SECURE_AUTH, &amp;amp;b); }
+if ((s = AG_GetStringP(db,"init-cmd")) != NULL) { mysql_options(my, MYSQL_INIT_COMMAND, s); }
+if ((s = AG_GetStringP(db,"cnf-file")) != NULL) { mysql_options(my, MYSQL_READ_DEFAULT_FILE, s); }
+if ((s = AG_GetStringP(db,"cnf-group")) != NULL) { mysql_options(my, MYSQL_READ_DEFAULT_GROUP, s); }
+
+if ((s = AG_GetStringP(db,"protocol")) != NULL) {
+switch (tolower(s[0])) {
+case 't':i = MYSQL_PROTOCOL_TCP;break;
+case 's':i = MYSQL_PROTOCOL_SOCKET;break;
+case 'p':i = MYSQL_PROTOCOL_PIPE;break;
+case 'm':i = MYSQL_PROTOCOL_MEMORY;break;
+default:i = MYSQL_PROTOCOL_DEFAULT;break;
+}
+mysql_options(my, MYSQL_OPT_PROTOCOL, &amp;amp;i);
+}
+if ((i = AG_GetUint(db,"read-timeout")) != 0) { mysql_options(my, MYSQL_OPT_READ_TIMEOUT, &amp;amp;i); }
+if ((i = AG_GetUint(db,"write-timeout")) != 0) { mysql_options(my, MYSQL_OPT_WRITE_TIMEOUT, &amp;amp;i); }
+if (AG_GetUint(db,"reconnect") == 1) { mysql_options(my, MYSQL_OPT_RECONNECT, &amp;amp;b); }
+
+if ((s = AG_GetStringP(db,"charset")) != NULL) { mysql_options(my, MYSQL_SET_CHARSET_NAME, s); }
+if ((s = AG_GetStringP(db,"charset-dir")) != NULL) { mysql_options(my, MYSQL_SET_CHARSET_DIR, s); }
+
+db-&amp;gt;my = mysql_real_connect(my,
+    AG_GetStringP(my,"host"),
+    AG_GetStringP(my,"user"),
+    AG_GetStringP(my,"pass"),
+    dbName,
+    AG_GetInt(my,"port"),
+    AG_GetString(my,"unix-socket"),
+    myFlags);
+if (db-&amp;gt;my == NULL) {
+AG_SetError("MySQL: %s", mysql_error(my))
+mysql_close(my);
+return (-1);
+}
+return (0);
+}
+
+static void
+Close(void *obj)
+{
+AG_DbMySQL *db = obj;
+
+mysql_close(db-&amp;gt;my);
+db-&amp;gt;my = NULL;
+}
+
+static int
+Exists(void *obj, AG_DbEntry *dbe)
+{
+AG_DbMySQL *db = obj;
+char *ks, *q;
+
+ks = EncodeKey(dbe);
+Asprintf(&amp;amp;q, AG_GetStringP(db,"get-cmd"), ks);
+Free(ks);
+if (mysql_query(db-&amp;gt;my, q) != 0) {
+AG_SetError("Get: %s", mysql_error(db-&amp;gt;my));
+return (-1);
+}
+Free(q);
+return (mysql_field_count(db-&amp;gt;my) &amp;gt; 0) ? 1 : 0
+}
+
+static int
+Get(void *obj, AG_DbEntry *dbe)
+{
+return (-1);
+}
+
+static int
+Put(void *obj, AG_DbEntry *dbe)
+{
+return (-1);
+}
+
+static int
+Del(void *obj, AG_DbEntry *dbe)
+{
+return (-1);
+}
+
+static int
+Iterate(void *obj, AG_DbIterateFn fn)
+{
+return (-1);
+}
+
+AG_DbClass agDbMySQLClass = {
+{
+"Agar(Db:DbMySQL)",
+sizeof(AG_DbMySQL),
+{ 0,0 },
+Init,
+NULL,/* free */
+NULL,/* destroy */
+NULL,/* load */
+NULL,/* save */
+NULL/* edit */
+},
+"mysql",
+N_("MySQL database interface"),
+AG_DB_KEY_DATA,/* Key is variable data */
+AG_DB_REC_VARIABLE,/* Variable-sized records */
+Open,
+Close
+NULL,/* sync */
+Exists,
+Get,
+Put,
+Del,
+Iterate
+};
+
+#endif /* HAVE_MYSQL */

Copied: trunk/core/text.c (from rev 9090, trunk/core/string.c)
===================================================================
--- trunk/core/text.c                        (rev 0)
+++ trunk/core/text.c2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,269 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * Copyright (c) 2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Multilanguage text structure.
+ */
+
+#include &amp;lt;core/core.h&amp;gt;
+
+/* Language codes (see string.h, iso639-gen.pl) */
+const char *agLanguageCodes[] = {
+        "??", "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba", "be", "bg", 
+        "bh", "bi", "bn", "bo", "br", "ca", "co", "cs", "cy", "da", "de", "dz", 
+        "el", "en", "eo", "es", "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", 
+        "ga", "gd", "gl", "gn", "gu", "ha", "he", "hi", "hr", "hu", "hy", "ia", 
+        "id", "ie", "ik", "is", "it", "iu", "ja", "jw", "ka", "kk", "kl", "km", 
+        "kn", "ko", "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv", "mg", "mi", 
+        "mk", "ml", "mn", "mo", "mr", "ms", "mt", "my", "na", "ne", "nl", "no", 
+        "oc", "om", "or", "pa", "pl", "ps", "pt", "qu", "rm", "rn", "ro", "ru", 
+        "rw", "sa", "sd", "sg", "sh", "si", "sk", "sl", "sm", "sn", "so", "sq", 
+        "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "ti", "tk", 
+        "tl", "tn", "to", "tr", "ts", "tt", "tw", "ug", "uk", "ur", "uz", "vi", 
+        "vo", "wo", "xh", "yi", "yo", "za", "zh", "zu"
+};
+const char *agLanguageNames[] = {
+N_("Undefined"),
+N_("Afar"),N_("Abkhazian"),N_("Afrikaans"),
+N_("Amharic"),N_("Arabic"),N_("Assamese"),
+N_("Aymara"),N_("Azerbaijani"),N_("Bashkir"),
+N_("Byelorussian"),N_("Bulgarian"),N_("Bihari"),
+N_("Bislama"),N_("Bengali; Bangla"),N_("Tibetan"),
+N_("Breton"),N_("Catalan"),N_("Corsican"),
+N_("Czech"),N_("Welsh"),N_("Danish"),
+N_("German"),N_("Bhutani"),N_("Greek"),
+N_("English"),N_("Esperanto"),N_("Spanish"),
+N_("Estonian"),N_("Basque"),N_("Persian"),
+N_("Finnish"),N_("Fiji"),N_("Faroese"),
+N_("French"),N_("Frisian"),N_("Irish"),
+N_("Scots Gaelic"),N_("Galician"),N_("Guarani"),
+N_("Gujarati"),N_("Hausa"),N_("Hebrew"),
+N_("Hindi"),N_("Croatian"),N_("Hungarian"),
+N_("Armenian"),N_("Interlingua"),N_("Indonesian"),
+N_("Interlingue"),N_("Inupiak"),N_("Icelandic"),
+N_("Italian"),N_("Inuktitut"),N_("Japanese"),
+N_("Javanese"),N_("Georgian"),N_("Kazakh"),
+N_("Greenlandic"),N_("Cambodian"),N_("Kannada"),
+N_("Korean"),N_("Kashmiri"),N_("Kurdish"),
+N_("Kirghiz"),N_("Latin"),N_("Lingala"),
+N_("Laothian"),N_("Lithuanian"),N_("Latvian, Lettish"),
+N_("Malagasy"),N_("Maori"),N_("Macedonian"),
+N_("Malayalam"),N_("Mongolian"),N_("Moldavian"),
+N_("Marathi"),N_("Malay"),N_("Maltese"),
+N_("Burmese"),N_("Nauru"),N_("Nepali"),
+N_("Dutch"),N_("Norwegian"),N_("Occitan"),
+N_("(Afan) Oromo"),N_("Oriya"),N_("Punjabi"),
+N_("Polish"),N_("Pashto, Pushto"),N_("Portuguese"),
+N_("Quechua"),N_("Rhaeto-Romance"),N_("Kirundi"),
+N_("Romanian"),N_("Russian"),N_("Kinyarwanda"),
+N_("Sanskrit"),N_("Sindhi"),N_("Sangho"),
+N_("Serbo-Croatian"),N_("Sinhalese"),N_("Slovak"),
+N_("Slovenian"),N_("Samoan"),N_("Shona"),
+N_("Somali"),N_("Albanian"),N_("Serbian"),
+N_("Siswati"),N_("Sesotho"),N_("Sundanese"),
+N_("Swedish"),N_("Swahili"),N_("Tamil"),
+N_("Telugu"),N_("Tajik"),N_("Thai"),
+N_("Tigrinya"),N_("Turkmen"),N_("Tagalog"),
+N_("Setswana"),N_("Tonga"),N_("Turkish"),
+N_("Tsonga"),N_("Tatar"),N_("Twi"),
+N_("Uighur"),N_("Ukrainian"),N_("Urdu"),
+N_("Uzbek"),N_("Vietnamese"),N_("Volapuk"),
+N_("Wolof"),N_("Xhosa"),N_("Yiddish"),
+N_("Yoruba"),N_("Zhuang"),N_("Chinese"),
+N_("Zulu")
+};
+
+/* Allocate a new string. Optionally s to set default text entry. */
+AG_Text *
+AG_TextNewS(const char *s)
+{
+AG_Text *txt;
+Uint i;
+
+if ((txt = AG_TryMalloc(sizeof(AG_Text))) == NULL) {
+return (NULL);
+}
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+AG_TextEnt *te = &amp;amp;txt-&amp;gt;ent[i];
+te-&amp;gt;buf = NULL;
+te-&amp;gt;bufSize = 0;
+te-&amp;gt;len = 0;
+}
+txt-&amp;gt;lang = AG_LANG_NONE;
+if (AG_MutexTryInit(&amp;amp;txt-&amp;gt;lock) == -1) {
+Free(txt);
+return (NULL);
+}
+if (s != NULL &amp;amp;&amp;amp;
+    AG_TextSetS(txt, s) == -1) {
+AG_TextFree(txt);
+return (NULL);
+}
+return (txt);
+}
+
+/* Allocate a new string. Optionally use format string to set default entry. */
+AG_Text *
+AG_TextNew(const char *fmt, ...)
+{
+AG_Text *txt;
+
+if ((txt = AG_TextNewS(NULL)) == NULL) {
+return (NULL);
+}
+if (fmt != NULL) {
+AG_TextEnt *se = &amp;amp;txt-&amp;gt;ent[AG_LANG_NONE];
+va_list ap;
+
+va_start(ap, fmt);
+if (vasprintf(&amp;amp;se-&amp;gt;buf, fmt, ap) == -1) {
+AG_TextFree(txt);
+return (NULL);
+}
+va_end(ap);
+se-&amp;gt;len = strlen(se-&amp;gt;buf);
+se-&amp;gt;bufSize = se-&amp;gt;len+1;
+}
+return (txt);
+}
+
+/* Free an AG_Text structure. */
+void
+AG_TextFree(AG_Text *txt)
+{
+int i;
+
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+Free(txt-&amp;gt;ent[i].buf);
+}
+AG_MutexDestroy(&amp;amp;txt-&amp;gt;lock);
+Free(txt);
+}
+
+/* Set text of current entry from format string */
+int
+AG_TextSet(AG_Text *txt , const char *fmt, ...)
+{
+AG_TextEnt *se = &amp;amp;txt-&amp;gt;ent[txt-&amp;gt;lang];
+va_list ap;
+
+Free(se-&amp;gt;buf);
+va_start(ap, fmt);
+if (vasprintf(&amp;amp;se-&amp;gt;buf, fmt, ap) == -1) {
+return (-1);
+}
+va_end(ap);
+se-&amp;gt;len = strlen(se-&amp;gt;buf);
+se-&amp;gt;bufSize = se-&amp;gt;len+1;
+return (0);
+}
+
+/* Set text of current entry from C string */
+int
+AG_TextSetS(AG_Text *txt, const char *s)
+{
+AG_TextEnt *se;
+char *sNew;
+
+if ((sNew = TryStrdup(s)) == NULL) {
+return (-1);
+}
+AG_MutexLock(&amp;amp;txt-&amp;gt;lock);
+se = &amp;amp;txt-&amp;gt;ent[txt-&amp;gt;lang];
+Free(se-&amp;gt;buf);
+se-&amp;gt;buf = sNew;
+se-&amp;gt;len = strlen(sNew);
+se-&amp;gt;bufSize = se-&amp;gt;len+1;
+AG_MutexUnlock(&amp;amp;txt-&amp;gt;lock);
+return (0);
+}
+
+/* Return ISO-639 code for current string language. */
+const char *
+AG_TextGetLangISO(AG_Text *txt)
+{
+const char *s;
+
+AG_MutexLock(&amp;amp;txt-&amp;gt;lock);
+s = agLanguageCodes[txt-&amp;gt;lang];
+AG_MutexUnlock(&amp;amp;txt-&amp;gt;lock);
+return (s);
+}
+
+/* Set current string language (per ISO-639 code) */
+int
+AG_TextSetLangISO(AG_Text *txt, const char *iso)
+{
+int i;
+
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+if (Strcasecmp(agLanguageCodes[i], iso) == 0)
+break;
+}
+if (i == AG_LANG_LAST) {
+AG_SetError("No such language: %s", iso);
+return (-1);
+}
+AG_MutexLock(&amp;amp;txt-&amp;gt;lock);
+txt-&amp;gt;lang = (enum ag_language)i;
+AG_MutexUnlock(&amp;amp;txt-&amp;gt;lock);
+return (0);
+}
+
+/* Duplicate a string. */
+AG_Text *
+AG_TextDup(AG_Text *txtSrc)
+{
+AG_Text *txtDst;
+int i;
+
+if ((txtDst = AG_TextNewS(NULL)) == NULL) {
+return (NULL);
+}
+AG_MutexLock(&amp;amp;txtDst-&amp;gt;lock);
+AG_MutexLock(&amp;amp;txtSrc-&amp;gt;lock);
+txtDst-&amp;gt;lang = txtSrc-&amp;gt;lang;
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+AG_TextEnt *se = &amp;amp;txtSrc-&amp;gt;ent[i];
+
+if (se-&amp;gt;buf != NULL) {
+AG_TextEnt *de = &amp;amp;txtDst-&amp;gt;ent[i];
+
+if ((de-&amp;gt;buf = TryStrdup(se-&amp;gt;buf)) == NULL) {
+goto fail;
+}
+de-&amp;gt;len = strlen(de-&amp;gt;buf);
+de-&amp;gt;bufSize = de-&amp;gt;len+1;
+}
+}
+AG_MutexUnlock(&amp;amp;txtDst-&amp;gt;lock);
+AG_MutexUnlock(&amp;amp;txtSrc-&amp;gt;lock);
+return (txtDst);
+fail:
+AG_MutexUnlock(&amp;amp;txtDst-&amp;gt;lock);
+AG_MutexUnlock(&amp;amp;txtSrc-&amp;gt;lock);
+AG_TextFree(txtDst);
+return (NULL);
+}

Copied: trunk/core/text.h (from rev 9090, trunk/core/string.h)
===================================================================
--- trunk/core/text.h                        (rev 0)
+++ trunk/core/text.h2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,245 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*Public domain*/
+
+#ifndef _AGAR_CORE_TEXT_H_
+#define _AGAR_CORE_TEXT_H_
+#include &amp;lt;agar/core/begin.h&amp;gt;
+
+/* Language code (see iso639-gen.pl) */
+enum ag_language {
+AG_LANG_NONE,/* Undefined */
+AG_LANG_AA,/* Afar */
+AG_LANG_AB,/* Abkhazian */
+AG_LANG_AF,/* Afrikaans */
+AG_LANG_AM,/* Amharic */
+AG_LANG_AR,/* Arabic */
+AG_LANG_AS,/* Assamese */
+AG_LANG_AY,/* Aymara */
+AG_LANG_AZ,/* Azerbaijani */
+AG_LANG_BA,/* Bashkir */
+AG_LANG_BE,/* Byelorussian */
+AG_LANG_BG,/* Bulgarian */
+AG_LANG_BH,/* Bihari */
+AG_LANG_BI,/* Bislama */
+AG_LANG_BN,/* Bengali; Bangla */
+AG_LANG_BO,/* Tibetan */
+AG_LANG_BR,/* Breton */
+AG_LANG_CA,/* Catalan */
+AG_LANG_CO,/* Corsican */
+AG_LANG_CS,/* Czech */
+AG_LANG_CY,/* Welsh */
+AG_LANG_DA,/* Danish */
+AG_LANG_DE,/* German */
+AG_LANG_DZ,/* Bhutani */
+AG_LANG_EL,/* Greek */
+AG_LANG_EN,/* English */
+AG_LANG_EO,/* Esperanto */
+AG_LANG_ES,/* Spanish */
+AG_LANG_ET,/* Estonian */
+AG_LANG_EU,/* Basque */
+AG_LANG_FA,/* Persian */
+AG_LANG_FI,/* Finnish */
+AG_LANG_FJ,/* Fiji */
+AG_LANG_FO,/* Faroese */
+AG_LANG_FR,/* French */
+AG_LANG_FY,/* Frisian */
+AG_LANG_GA,/* Irish */
+AG_LANG_GD,/* Scots Gaelic */
+AG_LANG_GL,/* Galician */
+AG_LANG_GN,/* Guarani */
+AG_LANG_GU,/* Gujarati */
+AG_LANG_HA,/* Hausa */
+AG_LANG_HE,/* Hebrew (formerly iw) */
+AG_LANG_HI,/* Hindi */
+AG_LANG_HR,/* Croatian */
+AG_LANG_HU,/* Hungarian */
+AG_LANG_HY,/* Armenian */
+AG_LANG_IA,/* Interlingua */
+AG_LANG_ID,/* Indonesian (formerly in) */
+AG_LANG_IE,/* Interlingue */
+AG_LANG_IK,/* Inupiak */
+AG_LANG_IS,/* Icelandic */
+AG_LANG_IT,/* Italian */
+AG_LANG_IU,/* Inuktitut */
+AG_LANG_JA,/* Japanese */
+AG_LANG_JW,/* Javanese */
+AG_LANG_KA,/* Georgian */
+AG_LANG_KK,/* Kazakh */
+AG_LANG_KL,/* Greenlandic */
+AG_LANG_KM,/* Cambodian */
+AG_LANG_KN,/* Kannada */
+AG_LANG_KO,/* Korean */
+AG_LANG_KS,/* Kashmiri */
+AG_LANG_KU,/* Kurdish */
+AG_LANG_KY,/* Kirghiz */
+AG_LANG_LA,/* Latin */
+AG_LANG_LN,/* Lingala */
+AG_LANG_LO,/* Laothian */
+AG_LANG_LT,/* Lithuanian */
+AG_LANG_LV,/* Latvian, Lettish */
+AG_LANG_MG,/* Malagasy */
+AG_LANG_MI,/* Maori */
+AG_LANG_MK,/* Macedonian */
+AG_LANG_ML,/* Malayalam */
+AG_LANG_MN,/* Mongolian */
+AG_LANG_MO,/* Moldavian */
+AG_LANG_MR,/* Marathi */
+AG_LANG_MS,/* Malay */
+AG_LANG_MT,/* Maltese */
+AG_LANG_MY,/* Burmese */
+AG_LANG_NA,/* Nauru */
+AG_LANG_NE,/* Nepali */
+AG_LANG_NL,/* Dutch */
+AG_LANG_NO,/* Norwegian */
+AG_LANG_OC,/* Occitan */
+AG_LANG_OM,/* (Afan) Oromo */
+AG_LANG_OR,/* Oriya */
+AG_LANG_PA,/* Punjabi */
+AG_LANG_PL,/* Polish */
+AG_LANG_PS,/* Pashto, Pushto */
+AG_LANG_PT,/* Portuguese */
+AG_LANG_QU,/* Quechua */
+AG_LANG_RM,/* Rhaeto-Romance */
+AG_LANG_RN,/* Kirundi */
+AG_LANG_RO,/* Romanian */
+AG_LANG_RU,/* Russian */
+AG_LANG_RW,/* Kinyarwanda */
+AG_LANG_SA,/* Sanskrit */
+AG_LANG_SD,/* Sindhi */
+AG_LANG_SG,/* Sangho */
+AG_LANG_SH,/* Serbo-Croatian */
+AG_LANG_SI,/* Sinhalese */
+AG_LANG_SK,/* Slovak */
+AG_LANG_SL,/* Slovenian */
+AG_LANG_SM,/* Samoan */
+AG_LANG_SN,/* Shona */
+AG_LANG_SO,/* Somali */
+AG_LANG_SQ,/* Albanian */
+AG_LANG_SR,/* Serbian */
+AG_LANG_SS,/* Siswati */
+AG_LANG_ST,/* Sesotho */
+AG_LANG_SU,/* Sundanese */
+AG_LANG_SV,/* Swedish */
+AG_LANG_SW,/* Swahili */
+AG_LANG_TA,/* Tamil */
+AG_LANG_TE,/* Telugu */
+AG_LANG_TG,/* Tajik */
+AG_LANG_TH,/* Thai */
+AG_LANG_TI,/* Tigrinya */
+AG_LANG_TK,/* Turkmen */
+AG_LANG_TL,/* Tagalog */
+AG_LANG_TN,/* Setswana */
+AG_LANG_TO,/* Tonga */
+AG_LANG_TR,/* Turkish */
+AG_LANG_TS,/* Tsonga */
+AG_LANG_TT,/* Tatar */
+AG_LANG_TW,/* Twi */
+AG_LANG_UG,/* Uighur */
+AG_LANG_UK,/* Ukrainian */
+AG_LANG_UR,/* Urdu */
+AG_LANG_UZ,/* Uzbek */
+AG_LANG_VI,/* Vietnamese */
+AG_LANG_VO,/* Volapuk */
+AG_LANG_WO,/* Wolof */
+AG_LANG_XH,/* Xhosa */
+AG_LANG_YI,/* Yiddish (formerly ji) */
+AG_LANG_YO,/* Yoruba */
+AG_LANG_ZA,/* Zhuang */
+AG_LANG_ZH,/* Chinese */
+AG_LANG_ZU,/* Zulu */
+AG_LANG_LAST
+};
+
+/* Text entry */
+typedef struct ag_text_ent {
+char  *buf;/* String buffer */
+size_t bufSize;/* Length (allocated) */
+size_t len;/* Length (chars) */
+} AG_TextEnt;
+
+/* Text object */
+typedef struct ag_text {
+AG_Mutex lock;
+AG_TextEnt ent[AG_LANG_LAST];/* Language entries */
+enum ag_language lang;/* Selected language */
+} AG_Text;
+
+#define AGTEXT(p) ((AG_Text *)(p))
+
+__BEGIN_DECLS
+extern const char *agLanguageCodes[];
+extern const char *agLanguageNames[];
+
+AG_Text    *AG_TextNew(const char *, ...);
+AG_Text    *AG_TextNewS(const char *);
+void        AG_TextFree(AG_Text *);
+int         AG_TextSet(AG_Text *, const char *, ...)
+                       FORMAT_ATTRIBUTE(__printf__, 2, 3);
+int         AG_TextSetS(AG_Text *, const char *);
+int         AG_TextSetLangISO(AG_Text *, const char *);
+const char *AG_TextGetLangISO(AG_Text *);
+AG_Text    *AG_TextDup(AG_Text *);
+
+static __inline__ void
+AG_TextSetLang(AG_Text *txt, enum ag_language lang)
+{
+AG_MutexLock(&amp;amp;txt-&amp;gt;lock);
+txt-&amp;gt;lang = lang;
+AG_MutexUnlock(&amp;amp;txt-&amp;gt;lock);
+}
+
+/* Grow buffer size of specified entry. */
+static __inline__ void
+AG_TextGrowEnt(AG_TextEnt *te, size_t len)
+{
+if (te-&amp;gt;len+len &amp;gt;= te-&amp;gt;bufSize) {
+te-&amp;gt;bufSize = te-&amp;gt;len + len + 32;
+te-&amp;gt;buf = AG_Realloc(te-&amp;gt;buf, te-&amp;gt;bufSize);
+}
+}
+
+/* Append a string to current entry. */
+static __inline__ void
+AG_TextCatS(AG_Text *txt, const char *s)
+{
+AG_TextEnt *te;
+size_t len;
+
+len = strlen(s);
+
+AG_MutexLock(&amp;amp;txt-&amp;gt;lock);
+te = &amp;amp;txt-&amp;gt;ent[txt-&amp;gt;lang];
+AG_TextGrowEnt(te, len+1);
+memcpy(&amp;amp;te-&amp;gt;buf[te-&amp;gt;len], s, len+1);
+te-&amp;gt;len += len;
+AG_MutexUnlock(&amp;amp;txt-&amp;gt;lock);
+}
+/* Append a character to current entry. */
+static __inline__ void
+AG_TextCatC(AG_Text *txt, const char c)
+{
+AG_TextEnt *te;
+
+AG_MutexLock(&amp;amp;txt-&amp;gt;lock);
+te = &amp;amp;txt-&amp;gt;ent[txt-&amp;gt;lang];
+AG_TextGrowEnt(te, 1);
+te-&amp;gt;buf[te-&amp;gt;len] = c;
+te-&amp;gt;buf[te-&amp;gt;len++] = '\0';
+AG_MutexUnlock(&amp;amp;txt-&amp;gt;lock);
+}
+/* Append an arbitrary block of bytes to current entry. */
+static __inline__ void
+AS_StringCatBytes(AG_Text *txt, const char *s, size_t len)
+{
+AG_TextEnt *te;
+
+AG_MutexLock(&amp;amp;txt-&amp;gt;lock);
+te = &amp;amp;txt-&amp;gt;ent[txt-&amp;gt;lang];
+AG_TextGrowEnt(te, len+1);
+memcpy(&amp;amp;te-&amp;gt;buf[te-&amp;gt;len], s, len);
+te-&amp;gt;len += len;
+AG_MutexUnlock(&amp;amp;txt-&amp;gt;lock);
+}
+__END_DECLS
+
+#include &amp;lt;agar/core/close.h&amp;gt;
+#endif /* _AGAR_CORE_TEXT_H_ */

Modified: trunk/core/variable.c
===================================================================
--- trunk/core/variable.c2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/variable.c2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1035,14 +1035,34 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return (NULL);
 }
 if (V-&amp;gt;fn.fnString != NULL) {
-s = Malloc(V-&amp;gt;info.size);
+if ((s = TryMalloc(V-&amp;gt;info.size)) == NULL) {
+goto fail;
+}
 (void)GetStringFn(obj, V, s, V-&amp;gt;info.size);
 } else {
 s = Strdup(V-&amp;gt;data.s);
 }
 AG_UnlockVariable(V);
 return (s);
+fail:
+AG_UnlockVariable(V);
+return (NULL);
 }
+/* Return a direct pointer to a string buffer (not free-threaded). */
+char *
+AG_GetStringP(void *pObj, const char *name)
+{
+AG_Object *obj = pObj;
+AG_Variable *V;
+char *s;
+
+if ((V = AG_GetVariableLocked(obj, name)) == NULL) {
+return (NULL);
+}
+s = V-&amp;gt;data.s;
+AG_UnlockVariable(V);
+return (s);
+}
 AG_Variable *
 AG_SetString(void *obj, const char *name, const char *s)
 {

Modified: trunk/core/variable.h
===================================================================
--- trunk/core/variable.h2012-02-17 02:49:30 UTC (rev 9090)
+++ trunk/core/variable.h2012-02-24 03:17:50 UTC (rev 9091)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -496,6 +496,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 size_t       AG_GetString(void *, const char *, char *, size_t)
          BOUNDED_ATTRIBUTE(__string__, 3, 4);
 char        *AG_GetStringDup(void *, const char *);
+char        *AG_GetStringP(void *, const char *);
 AG_Variable *AG_SetString(void *, const char *, const char *);
 AG_Variable *AG_SetStringNODUP(void *, const char *, char *);
 AG_Variable *AG_SetStringFixed(void *, const char *, char *, size_t)
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-02-24T03:17:51</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1404">
    <title>Agar: r9089 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1404</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-02-16 21:47:37 -0500 (Thu, 16 Feb 2012)
New Revision: 9089

Added:
   trunk/core/iso639-gen.pl
   trunk/core/string.c
   trunk/core/string.h
Modified:
   trunk/core/Makefile
   trunk/core/core.h
   trunk/core/core_begin.h
   trunk/core/core_pub.h
Log:
multilanguage strings



Modified: trunk/core/Makefile
===================================================================
--- trunk/core/Makefile2012-02-17 02:47:04 UTC (rev 9088)
+++ trunk/core/Makefile2012-02-17 02:47:37 UTC (rev 9089)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,7 +16,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 net_client.c net_command.c net_fgetln.c net_server.c \
 dir.c md5.c sha1.c rmd160.c file.c string_compat.c dso.c tree.c \
 time.c time_dummy.c time_gettimeofday.c time_win32.c time_condwait.c \
-db.c dbobject.c tbl.c getopt.c exec.c
+db.c dbobject.c tbl.c getopt.c exec.c string.c
 
 MAN3=AG_Intro.3 AG_Core.3 AG_Event.3 AG_Object.3 AG_Prop.3 AG_Timeout..3 \
 AG_Config.3 AG_Version.3 AG_DataSource.3 AG_Error.3 AG_Threads.3 \

Modified: trunk/core/core.h
===================================================================
--- trunk/core/core.h2012-02-17 02:47:04 UTC (rev 9088)
+++ trunk/core/core.h2012-02-17 02:47:37 UTC (rev 9089)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,9 +16,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;config/ag_threads.h&amp;gt;
 #include &amp;lt;config/ag_network.h&amp;gt;
 
-/* For threads types and use in inlines. */
-#include &amp;lt;core/threads.h&amp;gt;
-
 /* For inline routines */
 #include &amp;lt;config/_mk_have_stdlib_h.h&amp;gt;
 #ifdef _MK_HAVE_STDLIB_H
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -50,6 +47,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;core/error.h&amp;gt;
 #include &amp;lt;core/queue.h&amp;gt;
 #include &amp;lt;core/limits.h&amp;gt;
+#include &amp;lt;core/threads.h&amp;gt;
 
 #include &amp;lt;core/string_compat.h&amp;gt;
 #include &amp;lt;core/snprintf.h&amp;gt;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -94,6 +92,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;core/db.h&amp;gt;
 #include &amp;lt;core/dbobject.h&amp;gt;
 #include &amp;lt;core/exec.h&amp;gt;
+#include &amp;lt;core/string.h&amp;gt;
 
 #endif /* !_AGAR_CORE_CORE_H_ */
 #endif /* _AGAR_INTERNAL */

Modified: trunk/core/core_begin.h
===================================================================
--- trunk/core/core_begin.h2012-02-17 02:47:04 UTC (rev 9088)
+++ trunk/core/core_begin.h2012-02-17 02:47:37 UTC (rev 9089)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -4,6 +4,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;agar/config/ag_legacy.h&amp;gt;
 #include &amp;lt;agar/config/ag_threads.h&amp;gt;
 
+#include &amp;lt;agar/core/error.h&amp;gt;
 #include &amp;lt;agar/core/threads.h&amp;gt;
 
 #include &amp;lt;agar/config/_mk_have_stdlib_h.h&amp;gt;

Modified: trunk/core/core_pub.h
===================================================================
--- trunk/core/core_pub.h2012-02-17 02:47:04 UTC (rev 9088)
+++ trunk/core/core_pub.h2012-02-17 02:47:37 UTC (rev 9089)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -5,7 +5,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;agar/core/core_begin.h&amp;gt;
 
 #include &amp;lt;agar/core/core_init.h&amp;gt;
-#include &amp;lt;agar/core/error.h&amp;gt;
 #include &amp;lt;agar/core/string_compat.h&amp;gt;
 
 #ifdef _USE_AGAR_STD
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -36,6 +35,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;agar/core/dbobject.h&amp;gt;
 #include &amp;lt;agar/core/getopt.h&amp;gt;
 #include &amp;lt;agar/core/exec.h&amp;gt;
+#include &amp;lt;agar/core/string.h&amp;gt;
 
 #include &amp;lt;agar/core/core_close.h&amp;gt;
 #endif

Added: trunk/core/iso639-gen.pl
===================================================================
--- trunk/core/iso639-gen.pl                        (rev 0)
+++ trunk/core/iso639-gen.pl2012-02-17 02:47:37 UTC (rev 9089)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,47 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+#!/usr/bin/perl
+#
+# Public domain
+#
+# http://ftp.ics.uci.edu/pub/ietf/http/related/iso639.txt
+#
+
+my &amp;lt; at &amp;gt;ents = ();
+
+foreach $_ (&amp;lt;STDIN&amp;gt;) {
+chop;
+if (/^(\w\w) (.+)$/) {
+push &amp;lt; at &amp;gt;ents, $_;
+}
+}
+
+print "enum ag_language {\n";
+print "\tAG_LANG_NONE,\t/* Undefined */\n";
+foreach $_ (&amp;lt; at &amp;gt;ents) {
+if (/^(\w\w) (.+)$/) {
+print "\tAG_LANG_".uc($1).",\t/* ".$2." */\n";
+}
+}
+print "};\n";
+
+print "const char *agLanguageCodes[] = {\n";
+my $c = 1;
+print "\t\"??\", ";
+foreach $_ (&amp;lt; at &amp;gt;ents) {
+if (/^(\w\w) (.+)$/) {
+print "\"".$1."\", ";
+if ($c++ &amp;gt; 10) {
+print "\n\t";
+$c = 0;
+}
+}
+}
+print "};\n";
+
+print "const char *agLanguageNames[] = {\n";
+print "\tN_(\"Undefined\"),\n";
+foreach $_ (&amp;lt; at &amp;gt;ents) {
+if (/^(\w\w) (.+)$/) {
+print "\tN_(\"".$2."\"),\n";
+}
+}
+print "};\n";

Added: trunk/core/string.c
===================================================================
--- trunk/core/string.c                        (rev 0)
+++ trunk/core/string.c2012-02-17 02:47:37 UTC (rev 9089)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,359 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * Copyright (c) 2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * General-purpose multilanguage text structure.
+ */
+
+#include &amp;lt;core/core.h&amp;gt;
+
+/* Language codes (see string.h, iso639-gen.pl) */
+const char *agLanguageCodes[] = {
+        "??", "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba", "be", "bg", 
+        "bh", "bi", "bn", "bo", "br", "ca", "co", "cs", "cy", "da", "de", "dz", 
+        "el", "en", "eo", "es", "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", 
+        "ga", "gd", "gl", "gn", "gu", "ha", "he", "hi", "hr", "hu", "hy", "ia", 
+        "id", "ie", "ik", "is", "it", "iu", "ja", "jw", "ka", "kk", "kl", "km", 
+        "kn", "ko", "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv", "mg", "mi", 
+        "mk", "ml", "mn", "mo", "mr", "ms", "mt", "my", "na", "ne", "nl", "no", 
+        "oc", "om", "or", "pa", "pl", "ps", "pt", "qu", "rm", "rn", "ro", "ru", 
+        "rw", "sa", "sd", "sg", "sh", "si", "sk", "sl", "sm", "sn", "so", "sq", 
+        "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "ti", "tk", 
+        "tl", "tn", "to", "tr", "ts", "tt", "tw", "ug", "uk", "ur", "uz", "vi", 
+        "vo", "wo", "xh", "yi", "yo", "za", "zh", "zu"
+};
+const char *agLanguageNames[] = {
+N_("Undefined"),
+N_("Afar"),
+N_("Abkhazian"),
+N_("Afrikaans"),
+N_("Amharic"),
+N_("Arabic"),
+N_("Assamese"),
+N_("Aymara"),
+N_("Azerbaijani"),
+N_("Bashkir"),
+N_("Byelorussian"),
+N_("Bulgarian"),
+N_("Bihari"),
+N_("Bislama"),
+N_("Bengali; Bangla"),
+N_("Tibetan"),
+N_("Breton"),
+N_("Catalan"),
+N_("Corsican"),
+N_("Czech"),
+N_("Welsh"),
+N_("Danish"),
+N_("German"),
+N_("Bhutani"),
+N_("Greek"),
+N_("English"),
+N_("Esperanto"),
+N_("Spanish"),
+N_("Estonian"),
+N_("Basque"),
+N_("Persian"),
+N_("Finnish"),
+N_("Fiji"),
+N_("Faroese"),
+N_("French"),
+N_("Frisian"),
+N_("Irish"),
+N_("Scots Gaelic"),
+N_("Galician"),
+N_("Guarani"),
+N_("Gujarati"),
+N_("Hausa"),
+N_("Hebrew (formerly iw)"),
+N_("Hindi"),
+N_("Croatian"),
+N_("Hungarian"),
+N_("Armenian"),
+N_("Interlingua"),
+N_("Indonesian (formerly in)"),
+N_("Interlingue"),
+N_("Inupiak"),
+N_("Icelandic"),
+N_("Italian"),
+N_("Inuktitut"),
+N_("Japanese"),
+N_("Javanese"),
+N_("Georgian"),
+N_("Kazakh"),
+N_("Greenlandic"),
+N_("Cambodian"),
+N_("Kannada"),
+N_("Korean"),
+N_("Kashmiri"),
+N_("Kurdish"),
+N_("Kirghiz"),
+N_("Latin"),
+N_("Lingala"),
+N_("Laothian"),
+N_("Lithuanian"),
+N_("Latvian, Lettish"),
+N_("Malagasy"),
+N_("Maori"),
+N_("Macedonian"),
+N_("Malayalam"),
+N_("Mongolian"),
+N_("Moldavian"),
+N_("Marathi"),
+N_("Malay"),
+N_("Maltese"),
+N_("Burmese"),
+N_("Nauru"),
+N_("Nepali"),
+N_("Dutch"),
+N_("Norwegian"),
+N_("Occitan"),
+N_("(Afan) Oromo"),
+N_("Oriya"),
+N_("Punjabi"),
+N_("Polish"),
+N_("Pashto, Pushto"),
+N_("Portuguese"),
+N_("Quechua"),
+N_("Rhaeto-Romance"),
+N_("Kirundi"),
+N_("Romanian"),
+N_("Russian"),
+N_("Kinyarwanda"),
+N_("Sanskrit"),
+N_("Sindhi"),
+N_("Sangho"),
+N_("Serbo-Croatian"),
+N_("Sinhalese"),
+N_("Slovak"),
+N_("Slovenian"),
+N_("Samoan"),
+N_("Shona"),
+N_("Somali"),
+N_("Albanian"),
+N_("Serbian"),
+N_("Siswati"),
+N_("Sesotho"),
+N_("Sundanese"),
+N_("Swedish"),
+N_("Swahili"),
+N_("Tamil"),
+N_("Telugu"),
+N_("Tajik"),
+N_("Thai"),
+N_("Tigrinya"),
+N_("Turkmen"),
+N_("Tagalog"),
+N_("Setswana"),
+N_("Tonga"),
+N_("Turkish"),
+N_("Tsonga"),
+N_("Tatar"),
+N_("Twi"),
+N_("Uighur"),
+N_("Ukrainian"),
+N_("Urdu"),
+N_("Uzbek"),
+N_("Vietnamese"),
+N_("Volapuk"),
+N_("Wolof"),
+N_("Xhosa"),
+N_("Yiddish (formerly ji)"),
+N_("Yoruba"),
+N_("Zhuang"),
+N_("Chinese"),
+N_("Zulu")
+};
+
+/* Allocate a new string; if s argument is given, set as undefined language entry. */
+AG_String *
+AG_StringNewS(const char *s)
+{
+AG_String *as;
+Uint i;
+
+if ((as = AG_TryMalloc(sizeof(AG_String))) == NULL) {
+return (NULL);
+}
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+AG_StringEnt *se = &amp;amp;as-&amp;gt;ent[i];
+se-&amp;gt;buf = NULL;
+se-&amp;gt;bufSize = 0;
+se-&amp;gt;len = 0;
+}
+as-&amp;gt;lang = AG_LANG_NONE;
+if (AG_MutexTryInit(&amp;amp;as-&amp;gt;lock) == -1) {
+Free(as);
+return (NULL);
+}
+if (s != NULL &amp;amp;&amp;amp;
+    AG_StringSetS(as, s) == -1) {
+AG_StringFree(as);
+return (NULL);
+}
+return (as);
+}
+
+/* Allocate a new string; if fmt is non-NULL, set as undefined language entry. */
+AG_String *
+AG_StringNew(const char *fmt, ...)
+{
+AG_String *as;
+
+if ((as = AG_StringNewS(NULL)) == NULL) {
+return (NULL);
+}
+if (fmt != NULL) {
+AG_StringEnt *se = &amp;amp;as-&amp;gt;ent[AG_LANG_NONE];
+va_list ap;
+
+va_start(ap, fmt);
+if (vasprintf(&amp;amp;se-&amp;gt;buf, fmt, ap) == -1) {
+AG_StringFree(as);
+return (NULL);
+}
+va_end(ap);
+se-&amp;gt;len = strlen(se-&amp;gt;buf);
+se-&amp;gt;bufSize = se-&amp;gt;len+1;
+}
+return (as);
+}
+
+/* Free an AG_String structure. */
+void
+AG_StringFree(AG_String *as)
+{
+int i;
+
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+Free(as-&amp;gt;ent[i].buf);
+}
+AG_MutexDestroy(&amp;amp;as-&amp;gt;lock);
+Free(as);
+}
+
+/* Set current language entry (format string). */
+int
+AG_StringSet(AG_String *as, const char *fmt, ...)
+{
+AG_StringEnt *se = &amp;amp;as-&amp;gt;ent[as-&amp;gt;lang];
+va_list ap;
+
+Free(se-&amp;gt;buf);
+va_start(ap, fmt);
+if (vasprintf(&amp;amp;se-&amp;gt;buf, fmt, ap) == -1) {
+return (-1);
+}
+va_end(ap);
+se-&amp;gt;len = strlen(se-&amp;gt;buf);
+se-&amp;gt;bufSize = se-&amp;gt;len+1;
+return (0);
+}
+
+/* Set current language entry (C string). */
+int
+AG_StringSetS(AG_String *as, const char *s)
+{
+AG_StringEnt *se;
+char *sNew;
+
+if ((sNew = TryStrdup(s)) == NULL) {
+return (-1);
+}
+AG_MutexLock(&amp;amp;as-&amp;gt;lock);
+se = &amp;amp;as-&amp;gt;ent[as-&amp;gt;lang];
+Free(se-&amp;gt;buf);
+se-&amp;gt;buf = sNew;
+se-&amp;gt;len = strlen(sNew);
+se-&amp;gt;bufSize = se-&amp;gt;len+1;
+AG_MutexUnlock(&amp;amp;as-&amp;gt;lock);
+return (0);
+}
+
+/* Return ISO-639 code for current string language. */
+const char *
+AG_StringGetLangISO639(AG_String *as)
+{
+const char *s;
+
+AG_MutexLock(&amp;amp;as-&amp;gt;lock);
+s = agLanguageCodes[as-&amp;gt;lang];
+AG_MutexUnlock(&amp;amp;as-&amp;gt;lock);
+return (s);
+}
+
+/* Set current string language (per ISO-639 code) */
+int
+AG_StringSetLangISO639(AG_String *as, const char *iso)
+{
+int i;
+
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+if (Strcasecmp(agLanguageCodes[i], iso) == 0)
+break;
+}
+if (i == AG_LANG_LAST) {
+AG_SetError("No such language: %s", iso);
+return (-1);
+}
+as-&amp;gt;lang = (enum ag_language)i;
+return (0);
+}
+
+/* Duplicate a string. */
+AG_String *
+AG_StringDup(AG_String *ss)
+{
+AG_String *ds;
+int i;
+
+if ((ds = AG_StringNewS(NULL)) == NULL) {
+return (NULL);
+}
+AG_MutexLock(&amp;amp;ds-&amp;gt;lock);
+AG_MutexLock(&amp;amp;ss-&amp;gt;lock);
+ds-&amp;gt;lang = ss-&amp;gt;lang;
+for (i = 0; i &amp;lt; AG_LANG_LAST; i++) {
+AG_StringEnt *se = &amp;amp;ss-&amp;gt;ent[i];
+
+if (se-&amp;gt;buf != NULL) {
+AG_StringEnt *de = &amp;amp;ds-&amp;gt;ent[i];
+
+if ((de-&amp;gt;buf = TryStrdup(se-&amp;gt;buf)) == NULL) {
+goto fail;
+}
+de-&amp;gt;len = strlen(de-&amp;gt;buf);
+de-&amp;gt;bufSize = de-&amp;gt;len+1;
+}
+}
+AG_MutexUnlock(&amp;amp;ds-&amp;gt;lock);
+AG_MutexUnlock(&amp;amp;ss-&amp;gt;lock);
+return (ds);
+fail:
+AG_MutexUnlock(&amp;amp;ds-&amp;gt;lock);
+AG_MutexUnlock(&amp;amp;ss-&amp;gt;lock);
+AG_StringFree(ds);
+return (NULL);
+}

Added: trunk/core/string.h
===================================================================
--- trunk/core/string.h                        (rev 0)
+++ trunk/core/string.h2012-02-17 02:47:37 UTC (rev 9089)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,243 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*Public domain*/
+
+#ifndef _AGAR_CORE_STRING_H_
+#define _AGAR_CORE_STRING_H_
+#include &amp;lt;agar/core/begin.h&amp;gt;
+
+/* Language code (see iso639-gen.pl) */
+enum ag_language {
+AG_LANG_NONE,/* Undefined */
+AG_LANG_AA,/* Afar */
+AG_LANG_AB,/* Abkhazian */
+AG_LANG_AF,/* Afrikaans */
+AG_LANG_AM,/* Amharic */
+AG_LANG_AR,/* Arabic */
+AG_LANG_AS,/* Assamese */
+AG_LANG_AY,/* Aymara */
+AG_LANG_AZ,/* Azerbaijani */
+AG_LANG_BA,/* Bashkir */
+AG_LANG_BE,/* Byelorussian */
+AG_LANG_BG,/* Bulgarian */
+AG_LANG_BH,/* Bihari */
+AG_LANG_BI,/* Bislama */
+AG_LANG_BN,/* Bengali; Bangla */
+AG_LANG_BO,/* Tibetan */
+AG_LANG_BR,/* Breton */
+AG_LANG_CA,/* Catalan */
+AG_LANG_CO,/* Corsican */
+AG_LANG_CS,/* Czech */
+AG_LANG_CY,/* Welsh */
+AG_LANG_DA,/* Danish */
+AG_LANG_DE,/* German */
+AG_LANG_DZ,/* Bhutani */
+AG_LANG_EL,/* Greek */
+AG_LANG_EN,/* English */
+AG_LANG_EO,/* Esperanto */
+AG_LANG_ES,/* Spanish */
+AG_LANG_ET,/* Estonian */
+AG_LANG_EU,/* Basque */
+AG_LANG_FA,/* Persian */
+AG_LANG_FI,/* Finnish */
+AG_LANG_FJ,/* Fiji */
+AG_LANG_FO,/* Faroese */
+AG_LANG_FR,/* French */
+AG_LANG_FY,/* Frisian */
+AG_LANG_GA,/* Irish */
+AG_LANG_GD,/* Scots Gaelic */
+AG_LANG_GL,/* Galician */
+AG_LANG_GN,/* Guarani */
+AG_LANG_GU,/* Gujarati */
+AG_LANG_HA,/* Hausa */
+AG_LANG_HE,/* Hebrew (formerly iw) */
+AG_LANG_HI,/* Hindi */
+AG_LANG_HR,/* Croatian */
+AG_LANG_HU,/* Hungarian */
+AG_LANG_HY,/* Armenian */
+AG_LANG_IA,/* Interlingua */
+AG_LANG_ID,/* Indonesian (formerly in) */
+AG_LANG_IE,/* Interlingue */
+AG_LANG_IK,/* Inupiak */
+AG_LANG_IS,/* Icelandic */
+AG_LANG_IT,/* Italian */
+AG_LANG_IU,/* Inuktitut */
+AG_LANG_JA,/* Japanese */
+AG_LANG_JW,/* Javanese */
+AG_LANG_KA,/* Georgian */
+AG_LANG_KK,/* Kazakh */
+AG_LANG_KL,/* Greenlandic */
+AG_LANG_KM,/* Cambodian */
+AG_LANG_KN,/* Kannada */
+AG_LANG_KO,/* Korean */
+AG_LANG_KS,/* Kashmiri */
+AG_LANG_KU,/* Kurdish */
+AG_LANG_KY,/* Kirghiz */
+AG_LANG_LA,/* Latin */
+AG_LANG_LN,/* Lingala */
+AG_LANG_LO,/* Laothian */
+AG_LANG_LT,/* Lithuanian */
+AG_LANG_LV,/* Latvian, Lettish */
+AG_LANG_MG,/* Malagasy */
+AG_LANG_MI,/* Maori */
+AG_LANG_MK,/* Macedonian */
+AG_LANG_ML,/* Malayalam */
+AG_LANG_MN,/* Mongolian */
+AG_LANG_MO,/* Moldavian */
+AG_LANG_MR,/* Marathi */
+AG_LANG_MS,/* Malay */
+AG_LANG_MT,/* Maltese */
+AG_LANG_MY,/* Burmese */
+AG_LANG_NA,/* Nauru */
+AG_LANG_NE,/* Nepali */
+AG_LANG_NL,/* Dutch */
+AG_LANG_NO,/* Norwegian */
+AG_LANG_OC,/* Occitan */
+AG_LANG_OM,/* (Afan) Oromo */
+AG_LANG_OR,/* Oriya */
+AG_LANG_PA,/* Punjabi */
+AG_LANG_PL,/* Polish */
+AG_LANG_PS,/* Pashto, Pushto */
+AG_LANG_PT,/* Portuguese */
+AG_LANG_QU,/* Quechua */
+AG_LANG_RM,/* Rhaeto-Romance */
+AG_LANG_RN,/* Kirundi */
+AG_LANG_RO,/* Romanian */
+AG_LANG_RU,/* Russian */
+AG_LANG_RW,/* Kinyarwanda */
+AG_LANG_SA,/* Sanskrit */
+AG_LANG_SD,/* Sindhi */
+AG_LANG_SG,/* Sangho */
+AG_LANG_SH,/* Serbo-Croatian */
+AG_LANG_SI,/* Sinhalese */
+AG_LANG_SK,/* Slovak */
+AG_LANG_SL,/* Slovenian */
+AG_LANG_SM,/* Samoan */
+AG_LANG_SN,/* Shona */
+AG_LANG_SO,/* Somali */
+AG_LANG_SQ,/* Albanian */
+AG_LANG_SR,/* Serbian */
+AG_LANG_SS,/* Siswati */
+AG_LANG_ST,/* Sesotho */
+AG_LANG_SU,/* Sundanese */
+AG_LANG_SV,/* Swedish */
+AG_LANG_SW,/* Swahili */
+AG_LANG_TA,/* Tamil */
+AG_LANG_TE,/* Telugu */
+AG_LANG_TG,/* Tajik */
+AG_LANG_TH,/* Thai */
+AG_LANG_TI,/* Tigrinya */
+AG_LANG_TK,/* Turkmen */
+AG_LANG_TL,/* Tagalog */
+AG_LANG_TN,/* Setswana */
+AG_LANG_TO,/* Tonga */
+AG_LANG_TR,/* Turkish */
+AG_LANG_TS,/* Tsonga */
+AG_LANG_TT,/* Tatar */
+AG_LANG_TW,/* Twi */
+AG_LANG_UG,/* Uighur */
+AG_LANG_UK,/* Ukrainian */
+AG_LANG_UR,/* Urdu */
+AG_LANG_UZ,/* Uzbek */
+AG_LANG_VI,/* Vietnamese */
+AG_LANG_VO,/* Volapuk */
+AG_LANG_WO,/* Wolof */
+AG_LANG_XH,/* Xhosa */
+AG_LANG_YI,/* Yiddish (formerly ji) */
+AG_LANG_YO,/* Yoruba */
+AG_LANG_ZA,/* Zhuang */
+AG_LANG_ZH,/* Chinese */
+AG_LANG_ZU,/* Zulu */
+AG_LANG_LAST
+};
+
+typedef struct ag_string_ent {
+char  *buf;/* String buffer */
+size_t bufSize;/* Length (allocated) */
+size_t len;/* Length (chars) */
+} AG_StringEnt;
+
+typedef struct ag_string {
+AG_Mutex lock;
+AG_StringEnt ent[AG_LANG_LAST];/* Language entries */
+enum ag_language lang;/* Selected language */
+} AG_String;
+
+#define AGSTRING(p) ((AG_String *)(p))
+
+__BEGIN_DECLS
+extern const char *agLanguageCodes[];
+extern const char *agLanguageNames[];
+
+AG_String  *AG_StringNew(const char *, ...);
+AG_String  *AG_StringNewS(const char *);
+void        AG_StringFree(AG_String *);
+int         AG_StringSet(AG_String *, const char *, ...)
+                         FORMAT_ATTRIBUTE(__printf__, 2, 3);
+int         AG_StringSetS(AG_String *, const char *);
+int         AG_StringSetLangISO639(AG_String *, const char *);
+const char *AG_StringGetLangISO639(AG_String *);
+AG_String  *AG_StringDup(AG_String *);
+
+static __inline__ void
+AG_StringSetLang(AG_String *as, enum ag_language lang)
+{
+AG_MutexLock(&amp;amp;as-&amp;gt;lock);
+as-&amp;gt;lang = lang;
+AG_MutexUnlock(&amp;amp;as-&amp;gt;lock);
+}
+
+/* Grow buffer size of specified entry. */
+static __inline__ void
+AG_StringGrowEnt(AG_StringEnt *se, size_t len)
+{
+if (se-&amp;gt;len+len &amp;gt;= se-&amp;gt;bufSize) {
+se-&amp;gt;bufSize = se-&amp;gt;len + len + 32;
+se-&amp;gt;buf = AG_Realloc(se-&amp;gt;buf, se-&amp;gt;bufSize);
+}
+}
+
+/* Append a string to current language entry. */
+static __inline__ void
+AG_StringCatS(AG_String *as, const char *s)
+{
+AG_StringEnt *se;
+size_t len;
+
+len = strlen(s);
+
+AG_MutexLock(&amp;amp;as-&amp;gt;lock);
+se = &amp;amp;as-&amp;gt;ent[as-&amp;gt;lang];
+AG_StringGrowEnt(se, len+1);
+memcpy(&amp;amp;se-&amp;gt;buf[se-&amp;gt;len], s, len+1);
+se-&amp;gt;len += len;
+AG_MutexUnlock(&amp;amp;as-&amp;gt;lock);
+}
+/* Append a character to current language entry. */
+static __inline__ void
+AG_StringCatC(AG_String *as, const char c)
+{
+AG_StringEnt *se;
+
+AG_MutexLock(&amp;amp;as-&amp;gt;lock);
+se = &amp;amp;as-&amp;gt;ent[as-&amp;gt;lang];
+AG_StringGrowEnt(se, 1);
+se-&amp;gt;buf[se-&amp;gt;len] = c;
+se-&amp;gt;buf[se-&amp;gt;len++] = '\0';
+AG_MutexUnlock(&amp;amp;as-&amp;gt;lock);
+}
+/* Append block of bytes to current language entry. */
+static __inline__ void
+AS_StringCatBytes(AG_String *as, const char *s, size_t len)
+{
+AG_StringEnt *se;
+
+AG_MutexLock(&amp;amp;as-&amp;gt;lock);
+se = &amp;amp;as-&amp;gt;ent[as-&amp;gt;lang];
+AG_StringGrowEnt(se, len+1);
+memcpy(&amp;amp;se-&amp;gt;buf[se-&amp;gt;len], s, len);
+se-&amp;gt;len += len;
+AG_MutexUnlock(&amp;amp;as-&amp;gt;lock);
+}
+__END_DECLS
+
+#include &amp;lt;agar/core/close.h&amp;gt;
+#endif /* _AGAR_CORE_STRING_H_ */
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-02-17T02:47:37</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1403">
    <title>Agar: r9088 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1403</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-02-16 21:47:04 -0500 (Thu, 16 Feb 2012)
New Revision: 9088

Modified:
   trunk/core/threads.h
Log:
use inlines where appropriate; add missing Try* variants.



Modified: trunk/core/threads.h
===================================================================
--- trunk/core/threads.h2012-02-17 02:45:26 UTC (rev 9087)
+++ trunk/core/threads.h2012-02-17 02:47:04 UTC (rev 9088)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -31,54 +31,138 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 __END_DECLS
 #include &amp;lt;agar/core/close.h&amp;gt;
 
-#ifdef AG_DEBUG
+#define AG_ThreadSelf()pthread_self()
+#define AG_ThreadJoin(t,vp)pthread_join((t),(vp))
+#define AG_ThreadExit(p)pthread_exit(p)
+#define AG_ThreadKeyCreate(k)pthread_key_create(k,NULL)
+#define AG_ThreadKeyDelete(k)pthread_key_delete(k)
+#define AG_ThreadKeyGet(k)pthread_getspecific(k)
+#define AG_ThreadKeySet(k,v)pthread_setspecific((k),(v))
+#define AG_ThreadSigMask(how,n,o)pthread_sigmask((how),(n),(o))
+#define AG_ThreadKill(thread,signo)pthread_kill((thread),(signo))
+#define AG_MutexTryLock(m)pthread_mutex_trylock(m)
+#define AG_CondWait(cd,m)pthread_cond_wait(cd,m)
+#define AG_CondTimedWait(cd,m,t)pthread_cond_timedwait(cd,m,t)
 
-# define AG_MutexInit(m) if (pthread_mutex_init((m),NULL)!=0) abort()
-# define AG_MutexInitRecursive(m) if (pthread_mutex_init((m),&amp;amp;agRecursiveMutexAttr)!=0) abort()
-# define AG_MutexDestroy(m) if (pthread_mutex_destroy(m)!=0) abort()
-# define AG_MutexLock(m) if (pthread_mutex_lock(m)!=0) abort()
-# define AG_MutexUnlock(m) if (pthread_mutex_unlock(m)!=0) abort()
+/*
+ * Thread interface
+ */
+static __inline__ void
+AG_ThreadCreate(AG_Thread *th, void *(*fn)(void *), void *arg)
+{
+int rv;
+if ((rv = pthread_create(th, NULL, fn, arg)) != 0)
+AG_FatalError("AG_ThreadCreate (%d)", rv);
+}
+static __inline__ int
+AG_ThreadTryCreate(AG_Thread *th, void *(*fn)(void *), void *arg)
+{
+int rv;
+if ((rv = pthread_create(th, NULL, fn, arg)) != 0) {
+AG_SetError("pthread_create failed (%d)", rv);
+return (-1);
+}
+return (0);
+}
+static __inline__ void
+AG_ThreadCancel(AG_Thread th)
+{
+if (pthread_cancel(th) != 0)
+AG_FatalError("pthread_cancel failed");
+}
 
-# define AG_CondInit(cd) if (pthread_cond_init(cd,NULL)!=0) abort()
-# define AG_CondDestroy(cd) if (pthread_cond_destroy(cd)!=0) abort()
-# define AG_CondBroadcast(cd) if (pthread_cond_broadcast(cd)!=0) abort()
-# define AG_CondSignal(cd) if (pthread_cond_signal(cd)!=0) abort()
-# define AG_CondWait(cd,m) pthread_cond_wait(cd,m)
-# define AG_CondTimedWait(cd,m,t) pthread_cond_timedwait(cd,m,t)
+/*
+ * Mutex interface
+ */
+static __inline__ void
+AG_MutexInit(AG_Mutex *m)
+{
+if (pthread_mutex_init(m, NULL) != 0)
+AG_FatalError("AG_MutexInit");
+}
+static __inline__ void
+AG_MutexInitRecursive(AG_Mutex *m)
+{
+if (pthread_mutex_init(m, &amp;amp;agRecursiveMutexAttr) != 0)
+AG_FatalError("AG_MutexInitRecursive");
+}
+static __inline__ int
+AG_MutexTryInit(AG_Mutex *m)
+{
+int rv;
+if ((rv = pthread_mutex_init(m, NULL)) != 0) {
+AG_SetError("pthread_mutex_init failed (%d)", rv);
+return (-1);
+}
+return (0);
+}
+static __inline__ int
+AG_MutexTryInitRecursive(AG_Mutex *m)
+{
+int rv;
+if ((rv = pthread_mutex_init(m, &amp;amp;agRecursiveMutexAttr)) != 0) {
+AG_SetError("pthread_mutex_init failed (%d)", rv);
+return (-1);
+}
+return (0);
+}
+static __inline__ void
+AG_MutexLock(AG_Mutex *m)
+{
+if (pthread_mutex_lock(m) != 0)
+AG_FatalError("AG_MutexLock");
+}
+static __inline__ void
+AG_MutexUnlock(AG_Mutex *m)
+{
+if (pthread_mutex_unlock(m) != 0)
+AG_FatalError("AG_MutexUnlock");
+}
+static __inline__ void
+AG_MutexDestroy(AG_Mutex *m)
+{
+if (pthread_mutex_destroy(m) != 0)
+AG_FatalError("AG_MutexDestroy");
+}
 
-# define AG_ThreadCancel(t) if (pthread_cancel(t)!=0) abort();
+/*
+ * Condition variable interface
+ */
+static __inline__ void
+AG_CondInit(AG_Cond *cd)
+{
+if (pthread_cond_init(cd, NULL) != 0)
+AG_FatalError("AG_CondInit");
+}
+static __inline__ int
+AG_CondTryInit(AG_Cond *cd)
+{
+int rv;
+if ((rv = pthread_cond_init(cd, NULL)) != 0) {
+AG_SetError("pthread_cond_init failed (%d)", rv);
+return (-1);
+}
+return (0);
+}
+static __inline__ void
+AG_CondDestroy(AG_Cond *cd)
+{
+if (pthread_cond_destroy(cd) != 0)
+AG_FatalError("AG_CondDestroy");
+}
+static __inline__ void
+AG_CondBroadcast(AG_Cond *cd)
+{
+if (pthread_cond_broadcast(cd) != 0)
+AG_FatalError("AG_CondBroadcast");
+}
+static __inline__ void
+AG_CondSignal(AG_Cond *cd)
+{
+if (pthread_cond_signal(cd) != 0)
+AG_FatalError("AG_CondSignal");
+}
 
-#else /* !AG_DEBUG */
-
-# define AG_MutexInit(m) pthread_mutex_init((m),NULL)
-# define AG_MutexInitRecursive(m) pthread_mutex_init((m),&amp;amp;agRecursiveMutexAttr)
-# define AG_MutexDestroy(m) pthread_mutex_destroy(m)
-# define AG_MutexLock(m) pthread_mutex_lock(m)
-# define AG_MutexUnlock(m) pthread_mutex_unlock(m)
-
-# define AG_CondInit(cd) pthread_cond_init(cd,NULL)
-# define AG_CondDestroy(cd) pthread_cond_destroy(cd)
-# define AG_CondBroadcast(cd) pthread_cond_broadcast(cd)
-# define AG_CondSignal(cd) pthread_cond_signal(cd)
-# define AG_CondWait(cd,m) pthread_cond_wait(cd,m)
-# define AG_CondTimedWait(cd,m,t) pthread_cond_timedwait(cd,m,t)
-
-# define AG_ThreadCancel(t) pthread_cancel(t)
-
-#endif /* AG_DEBUG */
-
-#define AG_ThreadCreate(t,f,arg) pthread_create((t),NULL,(f),(arg))
-#define AG_ThreadSelf() pthread_self()
-#define AG_ThreadJoin(t,vp) pthread_join((t),(vp))
-#define AG_ThreadExit(p) pthread_exit(p)
-#define AG_MutexTryLock(m) pthread_mutex_trylock(m)
-#define AG_ThreadKeyCreate(k) pthread_key_create(k,NULL)
-#define AG_ThreadKeyDelete(k) pthread_key_delete(k)
-#define AG_ThreadKeyGet(k) pthread_getspecific(k)
-#define AG_ThreadKeySet(k,v) pthread_setspecific((k),(v))
-#define AG_ThreadSigMask(how,n,o) pthread_sigmask((how),(n),(o))
-#define AG_ThreadKill(thread,signo) pthread_kill((thread),(signo))
-
 #else /* !AG_THREADS */
 
 typedef int AG_Mutex;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -102,12 +186,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define AG_CondWait(cd,m)
 #define AG_CondTimedWait(cd,m,t)
 #define AG_ThreadCancel(thread)
-
 #define AG_ThreadSelf(thread) AG_FatalError("No AG_THREADS")
 #define AG_ThreadCreate(thread,func,arg) AG_FatalError("No AG_THREADS")
 #define AG_ThreadJoin(thread,valptr) AG_FatalError("No AG_THREADS")
 #define AG_ThreadExit(p)
-#define AG_MutexTryLock(m)
 #define AG_ThreadKeyCreate(k)
 #define AG_ThreadKeyDelete(k)
 #define AG_ThreadKeyGet(k)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -115,6 +197,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define AG_ThreadSigMask(how,newmask,oldmask)
 #define AG_ThreadKill(thread,signo)
 
+static __inline__ int AG_MutexTryInit(AG_Mutex *mutex) { return (0); }
+static __inline__ int AG_MutexTryInitRecursive(AG_Mutex *mutex) { return (0); }
+static __inline__ int AG_MutexTryLock(AG_Mutex *mutex) { return (0); }
+
 #undef HAVE_PTHREADS
 #endif /* AG_THREADS */
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-02-17T02:47:05</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1402">
    <title>Agar: r9090 - in trunk: dev gui</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1402</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-02-16 21:49:30 -0500 (Thu, 16 Feb 2012)
New Revision: 9090

Modified:
   trunk/dev/screenshot.c
   trunk/dev/server.c
   trunk/gui/anim.c
Log:
use AG_ThreadTryCreate()



Modified: trunk/dev/screenshot.c
===================================================================
--- trunk/dev/screenshot.c2012-02-17 02:47:37 UTC (rev 9089)
+++ trunk/dev/screenshot.c2012-02-17 02:49:30 UTC (rev 9090)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -265,9 +265,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     "This feature requires a single-display graphics driver");
 return;
 }
-if (AG_ThreadCreate(&amp;amp;thread, XmitThread, NULL) != 0) {
-AG_TextMsg(AG_MSG_ERROR, "Failed to create thread!");
-}
+if (AG_ThreadTryCreate(&amp;amp;thread, XmitThread, NULL) != 0)
+AG_TextMsgFromError();
 }
 
 static void

Modified: trunk/dev/server.c
===================================================================
--- trunk/dev/server.c2012-02-17 02:47:37 UTC (rev 9089)
+++ trunk/dev/server.c2012-02-17 02:49:30 UTC (rev 9090)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -321,8 +321,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 int
 DEV_DebugServerStart(void)
 {
-int rv;
-
 if (!server_inited) {
 AG_ObjectInitStatic(&amp;amp;server, &amp;amp;nsServerClass);
 AG_ObjectSetName(&amp;amp;server, "_DebugServer");
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -342,8 +340,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #endif
 server_inited = 1;
 }
-if ((rv = AG_ThreadCreate(&amp;amp;listenTh, ServerLoop, NULL)) != 0) {
-AG_TextMsg(AG_MSG_ERROR, "AG_ThreadCreate: %s", strerror(rv));
+if (AG_ThreadTryCreate(&amp;amp;listenTh, ServerLoop, NULL) != 0) {
+AG_TextMsgFromError();
 return (-1);
 }
 return (0);

Modified: trunk/gui/anim.c
===================================================================
--- trunk/gui/anim.c2012-02-17 02:47:37 UTC (rev 9089)
+++ trunk/gui/anim.c2012-02-17 02:49:30 UTC (rev 9090)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -432,7 +432,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_MutexLock(&amp;amp;ast-&amp;gt;lock);
 ast-&amp;gt;play = 1;
 #ifdef AG_THREADS
-if (AG_ThreadCreate(&amp;amp;ast-&amp;gt;th, AnimProc, ast) != 0) {
+if (AG_ThreadTryCreate(&amp;amp;ast-&amp;gt;th, AnimProc, ast) != 0) {
 AG_SetError("Failed to create playback thread");
 rv = -1;
 ast-&amp;gt;play = 0;
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-02-17T02:49:30</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1401">
    <title>Agar: r9084 - trunk/gui</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1401</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-01-14 03:36:55 -0500 (Sat, 14 Jan 2012)
New Revision: 9084

Modified:
   trunk/gui/widget.c
Log:
add missing unlock call in PollRedrawOnChange()!



Modified: trunk/gui/widget.c
===================================================================
--- trunk/gui/widget.c2012-01-14 07:41:07 UTC (rev 9083)
+++ trunk/gui/widget.c2012-01-14 08:36:55 UTC (rev 9084)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -267,6 +267,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if (wid-&amp;gt;window != NULL)
 wid-&amp;gt;window-&amp;gt;dirty = 1;
 }
+AG_UnlockVariable(V);
 return (ival);
 }
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-01-14T08:36:56</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1400">
    <title>Agar: r9082 - trunk/gui</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1400</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-01-14 02:40:44 -0500 (Sat, 14 Jan 2012)
New Revision: 9082

Modified:
   trunk/gui/AG_DirDlg.3
   trunk/gui/dir_dlg.c
   trunk/gui/dir_dlg.h
Log:
add AG_DIRDLG_NOBUTTONS option



Modified: trunk/gui/AG_DirDlg.3
===================================================================
--- trunk/gui/AG_DirDlg.32012-01-14 07:39:55 UTC (rev 9081)
+++ trunk/gui/AG_DirDlg.32012-01-14 07:40:44 UTC (rev 9082)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -82,7 +82,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 Acceptable
 .Fa flags
 include:
-.Bl -tag -width "AG_DIRDLG_CLOSEWIN "
+.Bl -tag -width "AG_DIRDLG_NOBUTTONS "
 .It AG_DIRDLG_MULTI
 Allow multiple directories to be selected at once.
 .It AG_DIRDLG_CLOSEWIN
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -97,6 +97,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .It AG_DIRDLG_ASYNC
 Load/save routines will be executed in a separate thread.
 This flag is available only if agar was compiled with threads support.
+.It AG_DIRDLG_NOBUTTONS
+Don't display "OK" and "Cancel" buttons.
 .It AG_DIRDLG_HFILL
 Expand horizontally in parent (equivalent to invoking
 .Xr AG_ExpandHoriz 3 ) .

Modified: trunk/gui/dir_dlg.c
===================================================================
--- trunk/gui/dir_dlg.c2012-01-14 07:39:55 UTC (rev 9081)
+++ trunk/gui/dir_dlg.c2012-01-14 07:40:44 UTC (rev 9082)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -64,6 +64,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 if (flags &amp;amp; AG_DIRDLG_HFILL) { AG_ExpandHoriz(dd); }
 if (flags &amp;amp; AG_DIRDLG_VFILL) { AG_ExpandVert(dd); }
 if (flags &amp;amp; AG_DIRDLG_MULTI) { dd-&amp;gt;tlDirs-&amp;gt;flags |= AG_TLIST_MULTI; }
+
+if (flags &amp;amp; AG_DIRDLG_NOBUTTONS) {
+AG_ObjectDetach(dd-&amp;gt;btnOk);
+AG_ObjectDetach(dd-&amp;gt;btnCancel);
+dd-&amp;gt;btnOk = NULL;
+dd-&amp;gt;btnCancel = NULL;
+}
 
 AG_ObjectAttach(parent, dd);
 return (dd);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -790,9 +797,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 r-&amp;gt;h = 4;
 AG_WidgetSizeReq(dd-&amp;gt;tbInput, &amp;amp;rChld);
 r-&amp;gt;h += rChld.h+2;
-AG_WidgetSizeReq(dd-&amp;gt;btnOk, &amp;amp;rOk);
-AG_WidgetSizeReq(dd-&amp;gt;btnCancel, &amp;amp;rCancel);
-r-&amp;gt;h += MAX(rOk.h,rCancel.h)+1;
+
+if (!(dd-&amp;gt;flags &amp;amp; AG_DIRDLG_NOBUTTONS)) {
+AG_WidgetSizeReq(dd-&amp;gt;btnOk, &amp;amp;rOk);
+AG_WidgetSizeReq(dd-&amp;gt;btnCancel, &amp;amp;rCancel);
+r-&amp;gt;h += MAX(rOk.h,rCancel.h)+1;
+}
 }
 
 static int
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -803,11 +813,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_SizeAlloc aChld;
 int hBtn = 0, wBtn = a-&amp;gt;w/2;
 
-AG_WidgetSizeReq(dd-&amp;gt;btnOk, &amp;amp;r);
-hBtn = MAX(hBtn, r.h);
-AG_WidgetSizeReq(dd-&amp;gt;btnCancel, &amp;amp;r);
-hBtn = MAX(hBtn, r.h);
-
+if (!(dd-&amp;gt;flags &amp;amp; AG_DIRDLG_NOBUTTONS)) {
+AG_WidgetSizeReq(dd-&amp;gt;btnOk, &amp;amp;r);
+hBtn = MAX(hBtn, r.h);
+AG_WidgetSizeReq(dd-&amp;gt;btnCancel, &amp;amp;r);
+hBtn = MAX(hBtn, r.h);
+}
+
 AG_WidgetSizeReq(dd-&amp;gt;comLoc, &amp;amp;rLoc);
 AG_WidgetSizeReq(dd-&amp;gt;tbInput, &amp;amp;rInput);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -829,16 +841,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 aChld.h = rInput.h;
 AG_WidgetSizeAlloc(dd-&amp;gt;tbInput, &amp;amp;aChld);
 
-/* Size buttons */
-aChld.y += aChld.h+2;
-aChld.w = wBtn;
-aChld.h = hBtn;
-AG_WidgetSizeAlloc(dd-&amp;gt;btnOk, &amp;amp;aChld);
-aChld.x = wBtn;
-if (wBtn*2 &amp;lt; a-&amp;gt;w) { aChld.w++; }
-aChld.h = hBtn;
-AG_WidgetSizeAlloc(dd-&amp;gt;btnCancel, &amp;amp;aChld);
-
+if (!(dd-&amp;gt;flags &amp;amp; AG_DIRDLG_NOBUTTONS)) {
+/* Size buttons */
+aChld.y += aChld.h+2;
+aChld.w = wBtn;
+aChld.h = hBtn;
+AG_WidgetSizeAlloc(dd-&amp;gt;btnOk, &amp;amp;aChld);
+aChld.x = wBtn;
+if (wBtn*2 &amp;lt; a-&amp;gt;w) { aChld.w++; }
+aChld.h = hBtn;
+AG_WidgetSizeAlloc(dd-&amp;gt;btnCancel, &amp;amp;aChld);
+}
 return (0);
 }
 

Modified: trunk/gui/dir_dlg.h
===================================================================
--- trunk/gui/dir_dlg.h2012-01-14 07:39:55 UTC (rev 9081)
+++ trunk/gui/dir_dlg.h2012-01-14 07:40:44 UTC (rev 9082)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -29,6 +29,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define AG_DIRDLG_HFILL0x100
 #define AG_DIRDLG_VFILL0x200
 #define AG_DIRDLG_EXPAND(AG_DIRDLG_HFILL|AG_DIRDLG_VFILL)
+#define AG_DIRDLG_NOBUTTONS0x400/* No OK/Cancel buttons */
 
 char cwd[AG_PATHNAME_MAX];/* Current working directory */
 AG_Tlist *tlDirs;/* List of directories */
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-01-14T07:40:44</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1399">
    <title>Agar: r9081 - in trunk: core dev</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1399</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-01-14 02:39:55 -0500 (Sat, 14 Jan 2012)
New Revision: 9081

Modified:
   trunk/core/.manlinks.mk
   trunk/core/object.c
   trunk/core/object.h
   trunk/dev/browser.c
Log:
remove undocumented AG_ObjectDuplicate() call



Modified: trunk/core/.manlinks.mk
===================================================================
--- trunk/core/.manlinks.mk2012-01-14 07:39:08 UTC (rev 9080)
+++ trunk/core/.manlinks.mk2012-01-14 07:39:55 UTC (rev 9081)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -103,6 +103,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 CATLINKS+=AG_Object.cat3:AG_ObjectFindParent.cat3
 MANLINKS+=AG_Object.3:AG_ObjectFindChild.3
 CATLINKS+=AG_Object.cat3:AG_ObjectFindChild.cat3
+MANLINKS+=AG_Object.3:AG_ObjectGetName.3
+CATLINKS+=AG_Object.cat3:AG_ObjectGetName.cat3
 MANLINKS+=AG_Object.3:AG_ObjectCopyName.3
 CATLINKS+=AG_Object.cat3:AG_ObjectCopyName.cat3
 MANLINKS+=AG_Object.3:AG_ObjectLock.3
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -527,6 +529,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 CATLINKS+=AG_Error.cat3:AG_TryRealloc.cat3
 MANLINKS+=AG_Error.3:AG_Free.3
 CATLINKS+=AG_Error.cat3:AG_Free.cat3
+MANLINKS+=AG_Threads.3:AG_Mutex.3
+CATLINKS+=AG_Threads.cat3:AG_Mutex.cat3
 MANLINKS+=AG_Threads.3:AG_MutexInit.3
 CATLINKS+=AG_Threads.cat3:AG_MutexInit.cat3
 MANLINKS+=AG_Threads.3:AG_MutexInitRecursive.3
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -539,6 +543,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 CATLINKS+=AG_Threads.cat3:AG_MutexTrylock.cat3
 MANLINKS+=AG_Threads.3:AG_MutexUnlock.3
 CATLINKS+=AG_Threads.cat3:AG_MutexUnlock.cat3
+MANLINKS+=AG_Threads.3:AG_Cond.3
+CATLINKS+=AG_Threads.cat3:AG_Cond.cat3
 MANLINKS+=AG_Threads.3:AG_CondInit.3
 CATLINKS+=AG_Threads.cat3:AG_CondInit.cat3
 MANLINKS+=AG_Threads.3:AG_CondDestroy.3
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -551,6 +557,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 CATLINKS+=AG_Threads.cat3:AG_CondWait.cat3
 MANLINKS+=AG_Threads.3:AG_CondTimedWait.3
 CATLINKS+=AG_Threads.cat3:AG_CondTimedWait.cat3
+MANLINKS+=AG_Threads.3:AG_Thread.3
+CATLINKS+=AG_Threads.cat3:AG_Thread.cat3
 MANLINKS+=AG_Threads.3:AG_ThreadCreate.3
 CATLINKS+=AG_Threads.cat3:AG_ThreadCreate.cat3
 MANLINKS+=AG_Threads.3:AG_ThreadCancel.3
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -561,6 +569,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 CATLINKS+=AG_Threads.cat3:AG_ThreadExit.cat3
 MANLINKS+=AG_Threads.3:AG_ThreadKill.3
 CATLINKS+=AG_Threads.cat3:AG_ThreadKill.cat3
+MANLINKS+=AG_Threads.3:AG_ThreadKey.3
+CATLINKS+=AG_Threads.cat3:AG_ThreadKey.cat3
 MANLINKS+=AG_Threads.3:AG_ThreadKeyCreate.3
 CATLINKS+=AG_Threads.cat3:AG_ThreadKeyCreate.cat3
 MANLINKS+=AG_Threads.3:AG_ThreadKeyDelete.3

Modified: trunk/core/object.c
===================================================================
--- trunk/core/object.c2012-01-14 07:39:08 UTC (rev 9080)
+++ trunk/core/object.c2012-01-14 07:39:55 UTC (rev 9081)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2192,51 +2192,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 AG_ObjectUnlock(ob);
 }
 
-/* Duplicate an object and its children. */
-/* XXX EXPERIMENTAL */
-void *
-AG_ObjectDuplicate(void *p, const char *newName)
-{
-char nameSave[AG_OBJECT_NAME_MAX];
-AG_Object *ob = p;
-AG_ObjectClass *cl = ob-&amp;gt;cls;
-AG_Object *dob;
-
-dob = Malloc(cl-&amp;gt;size);
-AG_ObjectLock(ob);
-AG_ObjectInit(dob, cl);
-AG_ObjectSetNameS(dob, newName);
-if (AG_ObjectPageIn(ob) == -1) {
-goto fail;
-}
-/* Change the name and attach to the same parent as the original. */
-AG_ObjectAttach(ob-&amp;gt;parent, dob);
-dob-&amp;gt;flags = (ob-&amp;gt;flags &amp;amp; AG_OBJECT_DUPED_FLAGS);
-
-/* Save the state of the original object using the new name. */
-/* XXX Save to temp location!! */
-Strlcpy(nameSave, ob-&amp;gt;name, sizeof(nameSave));
-Strlcpy(ob-&amp;gt;name, dob-&amp;gt;name, sizeof(ob-&amp;gt;name));
-if (AG_ObjectSave(ob) == -1) {
-AG_ObjectPageOut(ob);
-goto fail;
-}
-if (AG_ObjectPageOut(ob) == -1) {
-goto fail;
-}
-if (AG_ObjectLoad(dob) == -1) {
-goto fail;
-}
-Strlcpy(ob-&amp;gt;name, nameSave, sizeof(ob-&amp;gt;name));
-AG_ObjectUnlock(ob);
-return (dob);
-fail:
-Strlcpy(ob-&amp;gt;name, nameSave, sizeof(ob-&amp;gt;name));
-AG_ObjectUnlock(ob);
-AG_ObjectDestroy(dob);
-return (NULL);
-}
-
 /*
  * Return a cryptographic digest of an object's most recent archive. The
  * digest is accurate as long as the object is locked.

Modified: trunk/core/object.h
===================================================================
--- trunk/core/object.h2012-01-14 07:39:08 UTC (rev 9080)
+++ trunk/core/object.h2012-01-14 07:39:55 UTC (rev 9081)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -213,7 +213,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 void AG_ObjectMoveDown(void *);
 void AG_ObjectMoveToHead(void *);
 void AG_ObjectMoveToTail(void *);
-void*AG_ObjectDuplicate(void *, const char *);
 void AG_ObjectDestroy(void *);
 void AG_ObjectUnlinkDatafiles(void *);
 void AG_ObjectSetSavePfx(void *, char *);

Modified: trunk/dev/browser.c
===================================================================
--- trunk/dev/browser.c2012-01-14 07:39:08 UTC (rev 9080)
+++ trunk/dev/browser.c2012-01-14 07:39:55 UTC (rev 9081)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -429,24 +429,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 break;
 case OBJEDIT_DUP:
-{
-char dupName[AG_OBJECT_NAME_MAX];
-AG_Object *dob;
-
-if (ob == vfsRoot || !OBJECT_PERSISTENT(ob)) {
-AG_TextMsg(AG_MSG_ERROR,
-    _("%s: cannot duplicate."),
-    ob-&amp;gt;name);
-break;
-}
-AG_ObjectGenName(ob-&amp;gt;parent, ob-&amp;gt;cls, dupName,
-    sizeof(dupName));
-if ((dob = AG_ObjectDuplicate(ob, dupName))
-    == NULL) {
-AG_TextMsg(AG_MSG_ERROR, "%s: %s",
-    ob-&amp;gt;name, AG_GetError());
-}
-}
 break;
 case OBJEDIT_MOVE_UP:
 AG_ObjectMoveUp(ob);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -930,8 +912,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 AG_MenuSeparator(mi);
 
-AG_MenuAction(mi, _("Duplicate"), NULL,
-    ObjectOp, "%p,%p,%i", vfsRoot, tlObjs, OBJEDIT_DUP);
 AG_MenuActionKb(mi, _("Move up"), agIconUp.s,
     AG_KEY_U, AG_KEYMOD_SHIFT,
     ObjectOp, "%p,%p,%i", vfsRoot, tlObjs, OBJEDIT_MOVE_UP);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1037,8 +1017,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #endif /* AG_NETWORK */
 AG_MenuSeparator(mi);
 
-AG_MenuAction(mi, _("Duplicate"), NULL,
-    ObjectOp, "%p,%p,%i", vfsRoot, tlObjs, OBJEDIT_DUP);
 AG_MenuActionKb(mi, _("Move up"), agIconUp.s,
     AG_KEY_U, AG_KEYMOD_SHIFT,
     ObjectOp, "%p,%p,%i", vfsRoot, tlObjs,
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-01-14T07:39:55</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1398">
    <title>Agar: r9080 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1398</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-01-14 02:39:08 -0500 (Sat, 14 Jan 2012)
New Revision: 9080

Modified:
   trunk/core/AG_Threads.3
Log:
rewrite confusing example



Modified: trunk/core/AG_Threads.3
===================================================================
--- trunk/core/AG_Threads.32012-01-14 07:30:03 UTC (rev 9079)
+++ trunk/core/AG_Threads.32012-01-14 07:39:08 UTC (rev 9080)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -39,8 +39,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 multithreading.
 Agar API calls, unless otherwise documented, then become safe to invoke from
 arbitrary threads within an application.
-Internally this is achieved using many locking devices (e.g., mutexes),
-acquired and released in a fine-grained fashion.
+Internally this is achieved using fined-grained locking devices.
 .Pp
 The Agar object system (see
 .Xr AG_Object 3 )
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -54,37 +53,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 When multithreading is used, the return values of functions (except for error
 codes), should only be considered safe to use for as long as the related
 Agar objects are locked.
-Internally, the Agar functions will always acquire and release the necessary
-locks, but the calling function must be necessarily careful to avoid race
-conditions when a return value is used.
-For example, to disable a widget by name, the following code could be used:
+For example, the following code is unsafe:
 .Bd -literal -offset indent
-/* Thread unsafe */
-AG_Widget *myWidget;
-myWidget = AG_WidgetFind(agView, "MyWindow/MyWidget");
-if (widget != NULL) { AG_WidgetDisable(myWidget); }
+AG_Object *myObject;
+myObject = AG_ObjectFind(myRoot, "/Foo");
+if (myObject != NULL) { ... }/* UNSAFE */
 .Ed
 .Pp
-But if we execute this code from an arbitrary thread, there is a chance that
-the widget returned by
-.Fn AG_WidgetFind
-might have been destroyed before we reach
-.Fn AG_WidgetDisable .
-To avoid this race condition, the following is needed:
+The following code should be used instead:
 .Bd -literal -offset indent
-/* Thread safe */
-AG_Widget *myWidget;
-AG_ObjectLock(agView);
-myWidget = AG_WidgetFind(agView, "MyWindow/MyWidget");
-if (widget != NULL) { AG_WidgetDisable(myWidget); }
-AG_ObjectUnlock(agView);
+AG_Object *myObject;
+AG_ObjectLock(myRoot);
+myObject = AG_ObjectFind(myRoot, "/Foo");
+if (myObject != NULL) { ... }
+AG_ObjectUnlock(myRoot);
 .Ed
-.Pp
-This convention is important to thread safety, but this is a relatively rare
-usage since in practice, most GUI calls are made from event context, where it
-is safe to assume that
-.Va agView ,
-and the relevant widgets receiving the events, are already locked.
 .Sh THREADS INTERFACE
 When compiled with threads support, Agar provides a portable, minimal interface
 to the operating system's native threads interface.
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-01-14T07:39:08</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.agar.scm/1397">
    <title>Agar: r9079 - trunk/core</title>
    <link>http://comments.gmane.org/gmane.comp.lib.agar.scm/1397</link>
    <description>&lt;pre&gt;Author: vedge
Date: 2012-01-14 02:30:03 -0500 (Sat, 14 Jan 2012)
New Revision: 9079

Modified:
   trunk/core/AG_Threads.3
Log:
add manlinks for AG_Mutex, etc.



Modified: trunk/core/AG_Threads.3
===================================================================
--- trunk/core/AG_Threads.32012-01-06 08:59:44 UTC (rev 9078)
+++ trunk/core/AG_Threads.32012-01-14 07:30:03 UTC (rev 9079)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,4 +1,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-.\" Copyright (c) 2007-2010 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
+.\" Copyright (c) 2007-2012 Hypertriton, Inc. &amp;lt;http://hypertriton.com/&amp;gt;
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -89,6 +89,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 When compiled with threads support, Agar provides a portable, minimal interface
 to the operating system's native threads interface.
 .Sh MUTEXES
+.\" MANLINK(AG_Mutex)
 Mutexes (MUTual EXclusion devices) are commonly used to protect shared
 data structure against concurrent modifications.
 .Pp
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -137,6 +138,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Fn AG_MutexTrylock
 will raise a fatal condition if an error is encountered.
 .Sh CONDITION VARIABLES
+.\" MANLINK(AG_Cond)
 .nr nS 1
 .Ft "void"
 .Fn AG_CondInit "AG_Cond *cv"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -179,6 +181,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Pp
 All of these functions will raise a fatal condition if an error is encountered.
 .Sh THREADS
+.\" MANLINK(AG_Thread)
 .nr nS 1
 .Ft int
 .Fn AG_ThreadCreate "AG_Thread *th" "void *(*fn)(void *arg)" "void *arg"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -235,6 +238,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 .Pp
 .Sh THREAD-SPECIFIC VARIABLES
 .nr nS 1
+.\" MANLINK(AG_ThreadKey)
 .Ft int
 .Fn AG_ThreadKeyCreate "AG_ThreadKey *key"
 .Pp
&lt;/pre&gt;</description>
    <dc:creator>Agar-SVN</dc:creator>
    <dc:date>2012-01-14T07:30:03</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.comp.lib.agar.scm">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.comp.lib.agar.scm</link>
  </textinput>
</rdf:RDF>

