<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][15875] </title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=15875">15875</a></dd>
<dt>Author</dt> <dd>anthm</dd>
<dt>Date</dt> <dd>2009-12-10 14:51:13 -0600 (Thu, 10 Dec 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>Adding switch_mprintf (broken out from sqlite)
Adding new %w to mprintf to auto escape both single quote and backslashes
Improve the tab completion a tad and fix some sqlite/odbc compat with new mprintf opts
Change the default stream writer to use switch_vmprintf so %q/%w can be used there too</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchtrunkMakefileam">freeswitch/trunk/Makefile.am</a></li>
<li><a href="#freeswitchtrunksrcincludeswitchh">freeswitch/trunk/src/include/switch.h</a></li>
<li><a href="#freeswitchtrunksrcincludeswitch_core_dbh">freeswitch/trunk/src/include/switch_core_db.h</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiamod_sofiac">freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiasofiac">freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiasofia_gluec">freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c</a></li>
<li><a href="#freeswitchtrunksrcswitch_consolec">freeswitch/trunk/src/switch_console.c</a></li>
<li><a href="#freeswitchtrunksrcswitch_core_dbc">freeswitch/trunk/src/switch_core_db.c</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchtrunksrcincludeswitch_mprintfh">freeswitch/trunk/src/include/switch_mprintf.h</a></li>
<li><a href="#freeswitchtrunksrcswitch_mprintfc">freeswitch/trunk/src/switch_mprintf.c</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunkMakefileam"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/Makefile.am (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/Makefile.am        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/Makefile.am        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -67,6 +67,7 @@
</span><span class="cx"> src/switch_caller.c \
</span><span class="cx"> src/switch_channel.c \
</span><span class="cx"> src/switch_console.c \
</span><ins>+src/switch_mprintf.c\
</ins><span class="cx"> src/switch_core_media_bug.c \
</span><span class="cx"> src/switch_core_timer.c \
</span><span class="cx"> src/switch_core_asr.c \
</span><span class="lines">@@ -142,6 +143,7 @@
</span><span class="cx"> src/include/switch_scheduler.h\
</span><span class="cx"> src/include/switch_core.h\
</span><span class="cx"> src/include/switch_core_db.h\
</span><ins>+src/include/switch_mprintf.h\
</ins><span class="cx"> src/include/switch_config.h\
</span><span class="cx"> src/include/switch_event.h\
</span><span class="cx"> src/include/switch_frame.h\
</span></span></pre></div>
<a id="freeswitchtrunksrcincludeswitchh"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/include/switch.h (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/include/switch.h        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/src/include/switch.h        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx"> #include &quot;switch_platform.h&quot;
</span><span class="cx"> #include &quot;switch_types.h&quot;
</span><span class="cx"> #include &quot;switch_apr.h&quot;
</span><del>-
</del><ins>+#include &quot;switch_mprintf.h&quot;
</ins><span class="cx"> #include &quot;switch_core_db.h&quot;
</span><span class="cx"> #include &quot;switch_dso.h&quot;
</span><span class="cx"> #include &quot;switch_regex.h&quot;
</span></span></pre></div>
<a id="freeswitchtrunksrcincludeswitch_core_dbh"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/include/switch_core_db.h (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/include/switch_core_db.h        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/src/include/switch_core_db.h        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -539,13 +539,7 @@
</span><span class="cx">  * should always use %q instead of %s when inserting text into a string 
</span><span class="cx">  * literal.
</span><span class="cx">  */
</span><del>-SWITCH_DECLARE(char *) switch_mprintf(const char *zFormat, ...);
</del><span class="cx"> 
</span><del>-/*!
- * \see switch_mprintf
- */
-SWITCH_DECLARE(char *) switch_vmprintf(const char *zFormat, va_list ap);
-
</del><span class="cx"> SWITCH_END_EXTERN_C
</span><span class="cx"> #endif
</span><span class="cx"> /* For Emacs:
</span></span></pre></div>
<a id="freeswitchtrunksrcincludeswitch_mprintfh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/include/switch_mprintf.h (0 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/include/switch_mprintf.h                                (rev 0)
+++ freeswitch/trunk/src/include/switch_mprintf.h        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+/*
+** 2001 September 22
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+*/
+#ifndef SWITCH_MPRINTF_H
+#define SWITCH_MPRINTF_H
+
+SWITCH_BEGIN_EXTERN_C
+
+/**
+ * This routine is a variant of the &quot;sprintf()&quot; from the
+ * standard C library.  The resulting string is written into memory
+ * obtained from malloc() so that there is never a possiblity of buffer
+ * overflow.  This routine also implement some additional formatting
+ * options that are useful for constructing SQL statements.
+ *
+ * The strings returned by this routine should be freed by calling
+ * switch_core_db_free().
+ *
+ * All of the usual printf formatting options apply.  In addition, there
+ * is a &quot;%q&quot; option.  %q works like %s in that it substitutes a null-terminated
+ * string from the argument list.  But %q also doubles every '\'' character.
+ * %q is designed for use inside a string literal.  By doubling each '\''
+ * character it escapes that character and allows it to be inserted into
+ * the string.
+ *
+ * For example, so some string variable contains text as follows:
+ *
+ *      char *zText = &quot;It's a happy day!&quot;;
+ *
+ * We can use this text in an SQL statement as follows:
+ *
+ *      char *z = switch_core_db_mprintf(&quot;INSERT INTO TABLES('%q')&quot;, zText);
+ *      switch_core_db_exec(db, z, callback1, 0, 0);
+ *      switch_core_db_free(z);
+ *
+ * Because the %q format string is used, the '\'' character in zText
+ * is escaped and the SQL generated is as follows:
+ *
+ *      INSERT INTO table1 VALUES('It''s a happy day!')
+ *
+ * This is correct.  Had we used %s instead of %q, the generated SQL
+ * would have looked like this:
+ *
+ *      INSERT INTO table1 VALUES('It's a happy day!');
+ *
+ * This second example is an SQL syntax error.  As a general rule you
+ * should always use %q instead of %s when inserting text into a string
+ * literal.
+ */
+SWITCH_DECLARE(char *) switch_mprintf(const char *zFormat, ...);
+SWITCH_DECLARE(char *) switch_vmprintf(const char *zFormat, va_list ap);
+
+SWITCH_END_EXTERN_C
+#endif /* SWITCH_MPRINTF_H */
</ins></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiamod_sofiac"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -3744,6 +3744,18 @@
</span><span class="cx">         switch_console_set_complete(&quot;add sofia profile&quot;);
</span><span class="cx">         switch_console_set_complete(&quot;add sofia profile restart all&quot;);
</span><span class="cx"> 
</span><ins>+        switch_console_set_complete(&quot;add sofia profile _any_ start reloadxml&quot;);
+        switch_console_set_complete(&quot;add sofia profile _any_ stop reloadxml&quot;);
+        switch_console_set_complete(&quot;add sofia profile _any_ rescan reloadxml&quot;);
+        switch_console_set_complete(&quot;add sofia profile _any_ restart reloadxml&quot;);
+
+        switch_console_set_complete(&quot;add sofia profile _any_ flush_inbound_reg&quot;);
+        switch_console_set_complete(&quot;add sofia profile _any_ register&quot;);
+        switch_console_set_complete(&quot;add sofia profile _any_ killgw&quot;);
+        switch_console_set_complete(&quot;add sofia profile _any_ siptrace on&quot;);
+        switch_console_set_complete(&quot;add sofia profile _any_ siptrace off&quot;);
+
+
</ins><span class="cx">         SWITCH_ADD_API(api_interface, &quot;sofia_contact&quot;, &quot;Sofia Contacts&quot;, sofia_contact_function, &quot;[profile/]&lt;user&gt;@&lt;domain&gt;&quot;);
</span><span class="cx">         SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
</span><span class="cx"> 
</span><span class="lines">@@ -3755,6 +3767,8 @@
</span><span class="cx"> {
</span><span class="cx">         int sanity = 0;
</span><span class="cx"> 
</span><ins>+        switch_console_set_complete(&quot;del sofia&quot;);
+
</ins><span class="cx">         switch_mutex_lock(mod_sofia_globals.mutex);
</span><span class="cx">         if (mod_sofia_globals.running == 1) {
</span><span class="cx">                 mod_sofia_globals.running = 0;
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiasofiac"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -1059,7 +1059,7 @@
</span><span class="cx">         int sanity;
</span><span class="cx">         switch_thread_t *worker_thread;
</span><span class="cx">         switch_status_t st;
</span><del>-
</del><ins>+        char cbuf[512] = &quot;&quot;;
</ins><span class="cx">         
</span><span class="cx"> 
</span><span class="cx">         switch_mutex_lock(mod_sofia_globals.mutex);
</span><span class="lines">@@ -1226,10 +1226,17 @@
</span><span class="cx"> 
</span><span class="cx">         switch_yield(1000000);
</span><span class="cx"> 
</span><ins>+        switch_snprintf(cbuf, sizeof(cbuf), &quot;add sofia profile %s&quot;, profile-&gt;name);
+        switch_console_set_complete(cbuf);
+
+
</ins><span class="cx">         while (mod_sofia_globals.running == 1 &amp;&amp; sofia_test_pflag(profile, PFLAG_RUNNING) &amp;&amp; sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
</span><span class="cx">                 su_root_step(profile-&gt;s_root, 1000);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        switch_snprintf(cbuf, sizeof(cbuf), &quot;del sofia profile %s&quot;, profile-&gt;name);
+        switch_console_set_complete(cbuf);
+
</ins><span class="cx">         sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
</span><span class="cx"> 
</span><span class="cx">         switch_core_session_hupall_matching_var(&quot;sofia_profile_name&quot;, profile-&gt;name, SWITCH_CAUSE_MANAGER_REQUEST);
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiasofia_gluec"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -3644,10 +3644,12 @@
</span><span class="cx"> switch_status_t sofia_glue_add_profile(char *key, sofia_profile_t *profile)
</span><span class="cx"> {
</span><span class="cx">         switch_status_t status = SWITCH_STATUS_FALSE;
</span><del>-
</del><ins>+        char cbuf[512] = &quot;&quot;;
</ins><span class="cx">         switch_mutex_lock(mod_sofia_globals.hash_mutex);
</span><span class="cx">         if (!switch_core_hash_find(mod_sofia_globals.profile_hash, key)) {
</span><span class="cx">                 status = switch_core_hash_insert(mod_sofia_globals.profile_hash, key, profile);
</span><ins>+                switch_snprintf(cbuf, sizeof(cbuf), &quot;add sofia profile %s&quot;, key);
+                switch_console_set_complete(cbuf);
</ins><span class="cx">         }
</span><span class="cx">         switch_mutex_unlock(mod_sofia_globals.hash_mutex);
</span><span class="cx"> 
</span><span class="lines">@@ -3716,13 +3718,16 @@
</span><span class="cx">         const void *var;
</span><span class="cx">         void *val;
</span><span class="cx">         sofia_profile_t *pptr;
</span><del>-
</del><ins>+        char cbuf[512] = &quot;&quot;;
+        
</ins><span class="cx">         switch_mutex_lock(mod_sofia_globals.hash_mutex);
</span><span class="cx">         if (mod_sofia_globals.profile_hash) {
</span><span class="cx">                 for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
</span><span class="cx">                         switch_hash_this(hi, &amp;var, NULL, &amp;val);
</span><span class="cx">                         if ((pptr = (sofia_profile_t *) val) &amp;&amp; pptr == profile) {
</span><span class="cx">                                 aliases[i++] = strdup((char *) var);
</span><ins>+                                switch_snprintf(cbuf, sizeof(cbuf), &quot;del sofia profile %s&quot;, var);
+                                switch_console_set_complete(cbuf);
</ins><span class="cx">                                 if (i == 512) {
</span><span class="cx">                                         abort();
</span><span class="cx">                                 }
</span></span></pre></div>
<a id="freeswitchtrunksrcswitch_consolec"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/switch_console.c (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/switch_console.c        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/src/switch_console.c        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -122,7 +122,10 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         va_start(ap, fmt);
</span><del>-        ret = switch_vasprintf(&amp;data, fmt, ap);
</del><ins>+        //ret = switch_vasprintf(&amp;data, fmt, ap);
+        if (!(data = switch_vmprintf(fmt, ap))) {
+                ret = -1;
+        }
</ins><span class="cx">         va_end(ap);
</span><span class="cx"> 
</span><span class="cx">         if (data) {
</span><span class="lines">@@ -205,8 +208,13 @@
</span><span class="cx"> 
</span><span class="cx">         switch_core_db_handle(&amp;db);
</span><span class="cx"> 
</span><del>-        sql = switch_mprintf(&quot;select command from aliases where alias='%q'&quot;, cmd);
</del><span class="cx"> 
</span><ins>+        if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                sql = switch_mprintf(&quot;select command from aliases where alias='%q'&quot;, cmd);
+        } else {
+                sql = switch_mprintf(&quot;select command from aliases where alias='%w'&quot;, cmd);
+        }
+
</ins><span class="cx">         switch_cache_db_execute_sql_callback(db, sql, alias_callback, &amp;r, &amp;errmsg);
</span><span class="cx"> 
</span><span class="cx">         if (errmsg) {
</span><span class="lines">@@ -217,7 +225,11 @@
</span><span class="cx">         switch_safe_free(sql);
</span><span class="cx"> 
</span><span class="cx">         if (!r) {
</span><del>-                sql = switch_mprintf(&quot;select command from aliases where alias='%q %q'&quot;, cmd, arg);
</del><ins>+                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                        sql = switch_mprintf(&quot;select command from aliases where alias='%q %q'&quot;, cmd, arg);
+                } else {
+                        sql = switch_mprintf(&quot;select command from aliases where alias='%w %w'&quot;, cmd, arg);
+                }
</ins><span class="cx"> 
</span><span class="cx">                 switch_cache_db_execute_sql_callback(db, sql, alias_callback, &amp;r, &amp;errmsg);
</span><span class="cx"> 
</span><span class="lines">@@ -499,6 +511,7 @@
</span><span class="cx">         int hits;
</span><span class="cx">         int words;
</span><span class="cx">         char last[512];
</span><ins>+        char partial[512];
</ins><span class="cx">         FILE *out;
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -506,19 +519,37 @@
</span><span class="cx"> {
</span><span class="cx">         struct helper *h = (struct helper *) pArg;
</span><span class="cx">         char *target = NULL;
</span><del>-
</del><ins>+        switch_size_t x, y;
+        int i;
+        
</ins><span class="cx">         target = argv[0];
</span><span class="cx"> 
</span><span class="cx">         if (!target) {
</span><span class="cx">                 return -1;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        fprintf(h-&gt;out, &quot;[%20s]\t&quot;, target);
</del><ins>+        if (!zstr(target)) {
+                fprintf(h-&gt;out, &quot;[%20s]\t&quot;, target);
+                switch_copy_string(h-&gt;last, target, sizeof(h-&gt;last));
+                h-&gt;hits++;
+        }
+        
+        x = strlen(h-&gt;last);
+        y = strlen(h-&gt;partial);
</ins><span class="cx"> 
</span><del>-        switch_copy_string(h-&gt;last, target, sizeof(h-&gt;last));
</del><ins>+        if (h-&gt;hits &gt; 1) {
+                for(i = 0; i &lt; x &amp;&amp; i &lt; y; i++) {
+                        if (h-&gt;last[i] != h-&gt;partial[i]) {
+                                h-&gt;partial[i] = '\0';
+                                break;
+                        }
+                }        
+        } else if (h-&gt;hits == 1) {
+                switch_copy_string(h-&gt;partial, target, sizeof(h-&gt;last));
+        }
</ins><span class="cx"> 
</span><span class="cx">         if (!zstr(target)) {
</span><del>-                if ((++h-&gt;hits % 4) == 0) {
</del><ins>+                if ((h-&gt;hits % 4) == 0) {
</ins><span class="cx">                         fprintf(h-&gt;out, &quot;\n&quot;);
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="lines">@@ -600,8 +631,20 @@
</span><span class="cx"> 
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                for (x = 0; x &lt; argc; x++) {
-                        stream.write_function(&amp;stream, &quot;(a%d = '' or a%d like '%s%%')%s&quot;, x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? &quot;&quot; : &quot; and &quot;);
</del><ins>+                for (x = 0; x &lt; argc &amp;&amp; x &lt; 11; x++) {
+                        if (h.words + 1 &gt; argc) {
+                                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                                        stream.write_function(&amp;stream, &quot;(a%d = '' or a%d = '%q')%q&quot;, x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? &quot;&quot; : &quot; and &quot;);
+                                } else {
+                                        stream.write_function(&amp;stream, &quot;(a%d = '' or a%d = '%w')%w&quot;, x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? &quot;&quot; : &quot; and &quot;);
+                                }
+                        } else {
+                                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                                        stream.write_function(&amp;stream, &quot;(a%d = '' or a%d like '%q%%')%q&quot;, x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? &quot;&quot; : &quot; and &quot;);
+                                } else {
+                                        stream.write_function(&amp;stream, &quot;(a%d = '' or a%d like '%w%%')%w&quot;, x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? &quot;&quot; : &quot; and &quot;);
+                                }
+                        }
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 stream.write_function(&amp;stream, &quot; and hostname='%s'&quot;, switch_core_get_variable(&quot;hostname&quot;));
</span><span class="lines">@@ -624,9 +667,13 @@
</span><span class="cx"> 
</span><span class="cx">         fprintf(h.out, &quot;\n\n&quot;);
</span><span class="cx"> 
</span><del>-        if (h.hits == 1) {
</del><ins>+        if (h.hits == 1 &amp;&amp; !zstr(h.last)) {
</ins><span class="cx">                 el_deletestr(el, h.len);
</span><span class="cx">                 el_insertstr(el, h.last);
</span><ins>+                el_insertstr(el, &quot; &quot;);
+        } else if (h.hits &gt; 1 &amp;&amp; !zstr(h.partial)) {
+                el_deletestr(el, h.len);
+                el_insertstr(el, h.partial);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">   end:
</span><span class="lines">@@ -655,11 +702,19 @@
</span><span class="cx">                         SWITCH_STANDARD_STREAM(mystream);
</span><span class="cx"> 
</span><span class="cx">                         switch_core_db_handle(&amp;db);
</span><del>-                        
</del><ins>+
</ins><span class="cx">                         if (!strcasecmp(argv[0], &quot;stickyadd&quot;)) {
</span><span class="cx">                                 mystream.write_function(&amp;mystream, &quot;insert into complete values (1,&quot;);
</span><span class="cx">                                 for (x = 0; x &lt; 10; x++) {
</span><del>-                                        mystream.write_function(&amp;mystream, &quot;'%s', &quot;, switch_str_nil(argv[x + 1]));
</del><ins>+                                        if (argv[x + 1] &amp;&amp; !strcasecmp(argv[x + 1], &quot;_any_&quot;)) {
+                                                mystream.write_function(&amp;mystream, &quot;%s&quot;, &quot;'', &quot;);
+                                        } else {
+                                                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                                                        mystream.write_function(&amp;mystream, &quot;'%q', &quot;, switch_str_nil(argv[x + 1]));
+                                                } else {
+                                                        mystream.write_function(&amp;mystream, &quot;'%w', &quot;, switch_str_nil(argv[x + 1]));
+                                                }
+                                        }
</ins><span class="cx">                                 }
</span><span class="cx">                                 mystream.write_function(&amp;mystream, &quot; '%s')&quot;, switch_core_get_variable(&quot;hostname&quot;));
</span><span class="cx">                                 switch_cache_db_persistant_execute(db, mystream.data, 5);
</span><span class="lines">@@ -667,9 +722,18 @@
</span><span class="cx">                         } else if (!strcasecmp(argv[0], &quot;add&quot;)) {
</span><span class="cx">                                 mystream.write_function(&amp;mystream, &quot;insert into complete values (0,&quot;);
</span><span class="cx">                                 for (x = 0; x &lt; 10; x++) {
</span><del>-                                        mystream.write_function(&amp;mystream, &quot;'%s', &quot;, switch_str_nil(argv[x + 1]));
</del><ins>+                                        if (argv[x + 1] &amp;&amp; !strcasecmp(argv[x + 1], &quot;_any_&quot;)) {
+                                                mystream.write_function(&amp;mystream, &quot;%s&quot;, &quot;'', &quot;);
+                                        } else {
+                                                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                                                        mystream.write_function(&amp;mystream, &quot;'%q', &quot;, switch_str_nil(argv[x + 1]));
+                                                } else {
+                                                        mystream.write_function(&amp;mystream, &quot;'%w', &quot;, switch_str_nil(argv[x + 1]));
+                                                }
+                                        }
</ins><span class="cx">                                 }
</span><span class="cx">                                 mystream.write_function(&amp;mystream, &quot; '%s')&quot;, switch_core_get_variable(&quot;hostname&quot;));
</span><ins>+                                
</ins><span class="cx">                                 switch_cache_db_persistant_execute(db, mystream.data, 5);
</span><span class="cx">                                 status = SWITCH_STATUS_SUCCESS;
</span><span class="cx">                         } else if (!strcasecmp(argv[0], &quot;del&quot;)) {
</span><span class="lines">@@ -679,13 +743,18 @@
</span><span class="cx">                                 } else {
</span><span class="cx">                                         mystream.write_function(&amp;mystream, &quot;delete from complete where &quot;);
</span><span class="cx">                                         for (x = 0; x &lt; argc - 1; x++) {
</span><del>-                                                mystream.write_function(&amp;mystream, &quot;a%d = '%s'%s&quot;, x + 1, switch_str_nil(argv[x + 1]), x == argc - 2 ? &quot;&quot; : &quot; and &quot;);
</del><ins>+                                                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                                                        mystream.write_function(&amp;mystream, &quot;a%d = '%q'%q&quot;, x + 1, switch_str_nil(argv[x + 1]), x == argc - 2 ? &quot;&quot; : &quot; and &quot;);
+                                                } else {
+                                                        mystream.write_function(&amp;mystream, &quot;a%d = '%w'%w&quot;, x + 1, switch_str_nil(argv[x + 1]), x == argc - 2 ? &quot;&quot; : &quot; and &quot;);
+                                                }
</ins><span class="cx">                                         }
</span><span class="cx">                                         mystream.write_function(&amp;mystream, &quot; and hostname='%s'&quot;, switch_core_get_variable(&quot;hostname&quot;));
</span><span class="cx">                                         switch_cache_db_persistant_execute(db, mystream.data, 1);
</span><span class="cx">                                 }
</span><span class="cx">                                 status = SWITCH_STATUS_SUCCESS;
</span><span class="cx">                         }
</span><ins>+
</ins><span class="cx">                         switch_safe_free(mystream.data);
</span><span class="cx">                         switch_cache_db_release_db_handle(&amp;db);
</span><span class="cx">                 }
</span><span class="lines">@@ -715,16 +784,26 @@
</span><span class="cx">                                 sql = switch_mprintf(&quot;delete from aliases where alias='%q' and hostname='%q'&quot;, argv[1], switch_core_get_variable(&quot;hostname&quot;));
</span><span class="cx">                                 switch_cache_db_persistant_execute(db, sql, 5);
</span><span class="cx">                                 switch_safe_free(sql);
</span><del>-                                sql = switch_mprintf(&quot;insert into aliases (sticky, alias, command, hostname) values (1, '%q','%q','%q')&quot;, 
-                                                                         argv[1], argv[2], switch_core_get_variable(&quot;hostname&quot;));
</del><ins>+                                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                                        sql = switch_mprintf(&quot;insert into aliases (sticky, alias, command, hostname) values (1, '%q','%q','%q')&quot;, 
+                                                                                 argv[1], argv[2], switch_core_get_variable(&quot;hostname&quot;));
+                                } else {
+                                        sql = switch_mprintf(&quot;insert into aliases (sticky, alias, command, hostname) values (1, '%w','%w','%w')&quot;, 
+                                                                                 argv[1], argv[2], switch_core_get_variable(&quot;hostname&quot;));
+                                }
</ins><span class="cx">                                 switch_cache_db_persistant_execute(db, sql, 5);
</span><span class="cx">                                 status = SWITCH_STATUS_SUCCESS;
</span><span class="cx">                         } else if (!strcasecmp(argv[0], &quot;add&quot;) &amp;&amp; argc == 3) {
</span><span class="cx">                                 sql = switch_mprintf(&quot;delete from aliases where alias='%q' and hostname='%q'&quot;, argv[1], switch_core_get_variable(&quot;hostname&quot;));
</span><span class="cx">                                 switch_cache_db_persistant_execute(db, sql, 5);
</span><span class="cx">                                 switch_safe_free(sql);
</span><del>-                                sql = switch_mprintf(&quot;insert into aliases (sticky, alias, command, hostname) values (0, '%q','%q','%q')&quot;, 
-                                                                         argv[1], argv[2], switch_core_get_variable(&quot;hostname&quot;));
</del><ins>+                                if (db-&gt;type == SCDB_TYPE_CORE_DB) {
+                                        sql = switch_mprintf(&quot;insert into aliases (sticky, alias, command, hostname) values (0, '%q','%q','%q')&quot;, 
+                                                                                 argv[1], argv[2], switch_core_get_variable(&quot;hostname&quot;));
+                                } else {
+                                        sql = switch_mprintf(&quot;insert into aliases (sticky, alias, command, hostname) values (0, '%w','%w','%w')&quot;, 
+                                                                                 argv[1], argv[2], switch_core_get_variable(&quot;hostname&quot;));
+                                }
</ins><span class="cx">                                 switch_cache_db_persistant_execute(db, sql, 5);
</span><span class="cx">                                 status = SWITCH_STATUS_SUCCESS;
</span><span class="cx">                         } else if (!strcasecmp(argv[0], &quot;del&quot;) &amp;&amp; argc == 2) {
</span></span></pre></div>
<a id="freeswitchtrunksrcswitch_core_dbc"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/switch_core_db.c (15874 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/switch_core_db.c        2009-12-10 19:58:16 UTC (rev 15874)
+++ freeswitch/trunk/src/switch_core_db.c        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -179,22 +179,6 @@
</span><span class="cx">         return sqlite3_changes(db);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SWITCH_DECLARE(char *) switch_mprintf(const char *zFormat, ...)
-{
-        va_list ap;
-        char *z;
-        va_start(ap, zFormat);
-        z = sqlite3_vmprintf(zFormat, ap);
-        va_end(ap);
-        return z;
-}
-
-SWITCH_DECLARE(char *) switch_vmprintf(const char *zFormat, va_list ap)
-{
-
-        return sqlite3_vmprintf(zFormat, ap);
-}
-
</del><span class="cx"> SWITCH_DECLARE(switch_core_db_t *) switch_core_db_open_file(const char *filename)
</span><span class="cx"> {
</span><span class="cx">         switch_core_db_t *db;
</span></span></pre></div>
<a id="freeswitchtrunksrcswitch_mprintfc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/switch_mprintf.c (0 => 15875)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/switch_mprintf.c                                (rev 0)
+++ freeswitch/trunk/src/switch_mprintf.c        2009-12-10 20:51:13 UTC (rev 15875)
</span><span class="lines">@@ -0,0 +1,867 @@
</span><ins>+/*
+** The &quot;printf&quot; code that follows dates from the 1980's.  It is in
+** the public domain.  The original comments are included here for
+** completeness.  They are very out-of-date but might be useful as
+** an historical reference.  Most of the &quot;enhancements&quot; have been backed
+** out so that the functionality is now the same as standard printf().
+**
+**************************************************************************
+**
+** The following modules is an enhanced replacement for the &quot;printf&quot; subroutines
+** found in the standard C library.  The following enhancements are
+** supported:
+**
+**      +  Additional functions.  The standard set of &quot;printf&quot; functions
+**         includes printf, fprintf, sprintf, vprintf, vfprintf, and
+**         vsprintf.  This module adds the following:
+**
+**           *  snprintf -- Works like sprintf, but has an extra argument
+**                          which is the size of the buffer written to.
+**
+**           *  mprintf --  Similar to sprintf.  Writes output to memory
+**                          obtained from malloc.
+**
+**           *  xprintf --  Calls a function to dispose of output.
+**
+**           *  nprintf --  No output, but returns the number of characters
+**                          that would have been output by printf.
+**
+**           *  A v- version (ex: vsnprintf) of every function is also
+**              supplied.
+**
+**      +  A few extensions to the formatting notation are supported:
+**
+**           *  The &quot;=&quot; flag (similar to &quot;-&quot;) causes the output to be
+**              be centered in the appropriately sized field.
+**
+**           *  The %b field outputs an integer in binary notation.
+**
+**           *  The %c field now accepts a precision.  The character output
+**              is repeated by the number of times the precision specifies.
+**
+**           *  The %' field works like %c, but takes as its character the
+**              next character of the format string, instead of the next
+**              argument.  For example,  printf(&quot;%.78'-&quot;)  prints 78 minus
+**              signs, the same as  printf(&quot;%.78c&quot;,'-').
+**
+**      +  When compiled using GCC on a SPARC, this version of printf is
+**         faster than the library printf for SUN OS 4.1.
+**
+**      +  All functions are fully reentrant.
+**
+*/
+/*
+ * 20090210 (stkn):
+ *    Taken from sqlite-3.3.x,
+ *    renamed SQLITE_ -&gt; SWITCH_,
+ *    renamed visible functions to switch_*
+ *    disabled functions without extra conversion specifiers
+ */
+
+#include &lt;switch.h&gt;
+
+#define LONGDOUBLE_TYPE        long double
+
+/*
+** Conversion types fall into various categories as defined by the
+** following enumeration.
+*/
+#define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
+#define etFLOAT       2 /* Floating point.  %f */
+#define etEXP         3 /* Exponentional notation. %e and %E */
+#define etGENERIC     4 /* Floating or exponential, depending on exponent. %g */
+#define etSIZE        5 /* Return number of characters processed so far. %n */
+#define etSTRING      6 /* Strings. %s */
+#define etDYNSTRING   7 /* Dynamically allocated strings. %z */
+#define etPERCENT     8 /* Percent symbol. %% */
+#define etCHARX       9 /* Characters. %c */
+/* The rest are extensions, not normally found in printf() */
+#define etCHARLIT    10 /* Literal characters.  %' */
+#define etSQLESCAPE  11 /* Strings with '\'' doubled.  %q */
+#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',
+                          NULL pointers replaced by SQL NULL.  %Q */
+#ifdef __UNSUPPORTED__
+#define etTOKEN      13 /* a pointer to a Token structure */
+#define etSRCLIST    14 /* a pointer to a SrcList */
+#endif
+#define etPOINTER    15 /* The %p conversion */
+#define etSQLESCAPE3 16
+
+/*
+** An &quot;etByte&quot; is an 8-bit unsigned value.
+*/
+typedef unsigned char etByte;
+
+/*
+** Each builtin conversion character (ex: the 'd' in &quot;%d&quot;) is described
+** by an instance of the following structure
+*/
+typedef struct et_info {   /* Information about each format field */
+  char fmttype;            /* The format field code letter */
+  etByte base;             /* The base for radix conversion */
+  etByte flags;            /* One or more of FLAG_ constants below */
+  etByte type;             /* Conversion paradigm */
+  etByte charset;          /* Offset into aDigits[] of the digits string */
+  etByte prefix;           /* Offset into aPrefix[] of the prefix string */
+} et_info;
+
+/*
+** Allowed values for et_info.flags
+*/
+#define FLAG_SIGNED  1     /* True if the value to convert is signed */
+#define FLAG_INTERN  2     /* True if for internal use only */
+#define FLAG_STRING  4     /* Allow infinity precision */
+
+
+/*
+** The following table is searched linearly, so it is good to put the
+** most frequently used conversion types first.
+*/
+static const char aDigits[] = &quot;0123456789ABCDEF0123456789abcdef&quot;;
+static const char aPrefix[] = &quot;-x0\000X0&quot;;
+static const et_info fmtinfo[] = {
+  {  'd', 10, 1, etRADIX,      0,  0 },
+  {  's',  0, 4, etSTRING,     0,  0 },
+  {  'g',  0, 1, etGENERIC,    30, 0 },
+  {  'z',  0, 6, etDYNSTRING,  0,  0 },
+  {  'q',  0, 4, etSQLESCAPE,  0,  0 },
+  {  'Q',  0, 4, etSQLESCAPE2, 0,  0 },
+  {  'w',  0, 4, etSQLESCAPE3, 0,  0 },
+  {  'c',  0, 0, etCHARX,      0,  0 },
+  {  'o',  8, 0, etRADIX,      0,  2 },
+  {  'u', 10, 0, etRADIX,      0,  0 },
+  {  'x', 16, 0, etRADIX,      16, 1 },
+  {  'X', 16, 0, etRADIX,      0,  4 },
+#ifndef SWITCH_OMIT_FLOATING_POINT
+  {  'f',  0, 1, etFLOAT,      0,  0 },
+  {  'e',  0, 1, etEXP,        30, 0 },
+  {  'E',  0, 1, etEXP,        14, 0 },
+  {  'G',  0, 1, etGENERIC,    14, 0 },
+#endif
+  {  'i', 10, 1, etRADIX,      0,  0 },
+  {  'n',  0, 0, etSIZE,       0,  0 },
+  {  '%',  0, 0, etPERCENT,    0,  0 },
+  {  'p', 16, 0, etPOINTER,    0,  1 },
+#ifdef __UNSUPPORTED__
+  {  'T',  0, 2, etTOKEN,      0,  0 },
+  {  'S',  0, 2, etSRCLIST,    0,  0 },
+#endif
+};
+#define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
+
+/*
+** If SWITCH_OMIT_FLOATING_POINT is defined, then none of the floating point
+** conversions will work.
+*/
+#ifndef SWITCH_OMIT_FLOATING_POINT
+/*
+** &quot;*val&quot; is a double such that 0.1 &lt;= *val &lt; 10.0
+** Return the ascii code for the leading digit of *val, then
+** multiply &quot;*val&quot; by 10.0 to renormalize.
+**
+** Example:
+**     input:     *val = 3.14159
+**     output:    *val = 1.4159    function return = '3'
+**
+** The counter *cnt is incremented each time.  After counter exceeds
+** 16 (the number of significant digits in a 64-bit float) '0' is
+** always returned.
+*/
+static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
+  int digit;
+  LONGDOUBLE_TYPE d;
+  if( (*cnt)++ &gt;= 16 ) return '0';
+  digit = (int)*val;
+  d = digit;
+  digit += '0';
+  *val = (*val - d)*10.0;
+  return digit;
+}
+#endif /* SWITCH_OMIT_FLOATING_POINT */
+
+/*
+** On machines with a small stack size, you can redefine the
+** SWITCH_PRINT_BUF_SIZE to be less than 350.  But beware - for
+** smaller values some %f conversions may go into an infinite loop.
+*/
+#ifndef SWITCH_PRINT_BUF_SIZE
+# define SWITCH_PRINT_BUF_SIZE 350
+#endif
+#define etBUFSIZE SWITCH_PRINT_BUF_SIZE  /* Size of the output buffer */
+
+/*
+** The root program.  All variations call this core.
+**
+** INPUTS:
+**   func   This is a pointer to a function taking three arguments
+**            1. A pointer to anything.  Same as the &quot;arg&quot; parameter.
+**            2. A pointer to the list of characters to be output
+**               (Note, this list is NOT null terminated.)
+**            3. An integer number of characters to be output.
+**               (Note: This number might be zero.)
+**
+**   arg    This is the pointer to anything which will be passed as the
+**          first argument to &quot;func&quot;.  Use it for whatever you like.
+**
+**   fmt    This is the format string, as in the usual print.
+**
+**   ap     This is a pointer to a list of arguments.  Same as in
+**          vfprint.
+**
+** OUTPUTS:
+**          The return value is the total number of characters sent to
+**          the function &quot;func&quot;.  Returns -1 on a error.
+**
+** Note that the order in which automatic variables are declared below
+** seems to make a big difference in determining how fast this beast
+** will run.
+*/
+static int vxprintf(
+  void (*func)(void*,const char*,int),     /* Consumer of text */
+  void *arg,                         /* First argument to the consumer */
+  int useExtended,                   /* Allow extended %-conversions */
+  const char *fmt,                   /* Format string */
+  va_list ap                         /* arguments */
+){
+  int c;                     /* Next character in the format string */
+  char *bufpt;               /* Pointer to the conversion buffer */
+  int precision;             /* Precision of the current field */
+  int length;                /* Length of the field */
+  int idx;                   /* A general purpose loop counter */
+  int count;                 /* Total number of characters output */
+  int width;                 /* Width of the current field */
+  etByte flag_leftjustify;   /* True if &quot;-&quot; flag is present */
+  etByte flag_plussign;      /* True if &quot;+&quot; flag is present */
+  etByte flag_blanksign;     /* True if &quot; &quot; flag is present */
+  etByte flag_alternateform; /* True if &quot;#&quot; flag is present */
+  etByte flag_altform2;      /* True if &quot;!&quot; flag is present */
+  etByte flag_zeropad;       /* True if field width constant starts with zero */
+  etByte flag_long;          /* True if &quot;l&quot; flag is present */
+  etByte flag_longlong;      /* True if the &quot;ll&quot; flag is present */
+  etByte done;               /* Loop termination flag */
+  uint64_t longvalue;   /* Value for integer types */
+  LONGDOUBLE_TYPE realvalue; /* Value for real types */
+  const et_info *infop;      /* Pointer to the appropriate info structure */
+  char buf[etBUFSIZE];       /* Conversion buffer */
+  char prefix;               /* Prefix character.  &quot;+&quot; or &quot;-&quot; or &quot; &quot; or '\0'. */
+  etByte errorflag = 0;      /* True if an error is encountered */
+  etByte xtype;              /* Conversion paradigm */
+  char *zExtra;              /* Extra memory used for etTCLESCAPE conversions */
+  static const char spaces[] =
+   &quot;                                                                         &quot;;
+#define etSPACESIZE (sizeof(spaces)-1)
+#ifndef SWITCH_OMIT_FLOATING_POINT
+  int  exp, e2;              /* exponent of real numbers */
+  double rounder;            /* Used for rounding floating point values */
+  etByte flag_dp;            /* True if decimal point should be shown */
+  etByte flag_rtz;           /* True if trailing zeros should be removed */
+  etByte flag_exp;           /* True to force display of the exponent */
+  int nsd;                   /* Number of significant digits returned */
+#endif
+
+  func(arg,&quot;&quot;,0);
+  count = length = 0;
+  bufpt = 0;
+  for(; (c=(*fmt))!=0; ++fmt){
+    if( c!='%' ){
+      int amt;
+      bufpt = (char *)fmt;
+      amt = 1;
+      while( (c=(*++fmt))!='%' &amp;&amp; c!=0 ) amt++;
+      (*func)(arg,bufpt,amt);
+      count += amt;
+      if( c==0 ) break;
+    }
+    if( (c=(*++fmt))==0 ){
+      errorflag = 1;
+      (*func)(arg,&quot;%&quot;,1);
+      count++;
+      break;
+    }
+    /* Find out what flags are present */
+    flag_leftjustify = flag_plussign = flag_blanksign = 
+     flag_alternateform = flag_altform2 = flag_zeropad = 0;
+    done = 0;
+    do{
+      switch( c ){
+        case '-':   flag_leftjustify = 1;     break;
+        case '+':   flag_plussign = 1;        break;
+        case ' ':   flag_blanksign = 1;       break;
+        case '#':   flag_alternateform = 1;   break;
+        case '!':   flag_altform2 = 1;        break;
+        case '0':   flag_zeropad = 1;         break;
+        default:    done = 1;                 break;
+      }
+    }while( !done &amp;&amp; (c=(*++fmt))!=0 );
+    /* Get the field width */
+    width = 0;
+    if( c=='*' ){
+      width = va_arg(ap,int);
+      if( width&lt;0 ){
+        flag_leftjustify = 1;
+        width = -width;
+      }
+      c = *++fmt;
+    }else{
+      while( c&gt;='0' &amp;&amp; c&lt;='9' ){
+        width = width*10 + c - '0';
+        c = *++fmt;
+      }
+    }
+    if( width &gt; etBUFSIZE-10 ){
+      width = etBUFSIZE-10;
+    }
+    /* Get the precision */
+    if( c=='.' ){
+      precision = 0;
+      c = *++fmt;
+      if( c=='*' ){
+        precision = va_arg(ap,int);
+        if( precision&lt;0 ) precision = -precision;
+        c = *++fmt;
+      }else{
+        while( c&gt;='0' &amp;&amp; c&lt;='9' ){
+          precision = precision*10 + c - '0';
+          c = *++fmt;
+        }
+      }
+    }else{
+      precision = -1;
+    }
+    /* Get the conversion type modifier */
+    if( c=='l' ){
+      flag_long = 1;
+      c = *++fmt;
+      if( c=='l' ){
+        flag_longlong = 1;
+        c = *++fmt;
+      }else{
+        flag_longlong = 0;
+      }
+    }else{
+      flag_long = flag_longlong = 0;
+    }
+    /* Fetch the info entry for the field */
+    infop = 0;
+    for(idx=0; idx&lt;etNINFO; idx++){
+      if( c==fmtinfo[idx].fmttype ){
+        infop = &amp;fmtinfo[idx];
+        if( useExtended || (infop-&gt;flags &amp; FLAG_INTERN)==0 ){
+          xtype = infop-&gt;type;
+        }else{
+          return -1;
+        }
+        break;
+      }
+    }
+    zExtra = 0;
+    if( infop==0 ){
+      return -1;
+    }
+
+
+    /* Limit the precision to prevent overflowing buf[] during conversion */
+    if( precision&gt;etBUFSIZE-40 &amp;&amp; (infop-&gt;flags &amp; FLAG_STRING)==0 ){
+      precision = etBUFSIZE-40;
+    }
+
+    /*
+    ** At this point, variables are initialized as follows:
+    **
+    **   flag_alternateform          TRUE if a '#' is present.
+    **   flag_altform2               TRUE if a '!' is present.
+    **   flag_plussign               TRUE if a '+' is present.
+    **   flag_leftjustify            TRUE if a '-' is present or if the
+    **                               field width was negative.
+    **   flag_zeropad                TRUE if the width began with 0.
+    **   flag_long                   TRUE if the letter 'l' (ell) prefixed
+    **                               the conversion character.
+    **   flag_longlong               TRUE if the letter 'll' (ell ell) prefixed
+    **                               the conversion character.
+    **   flag_blanksign              TRUE if a ' ' is present.
+    **   width                       The specified field width.  This is
+    **                               always non-negative.  Zero is the default.
+    **   precision                   The specified precision.  The default
+    **                               is -1.
+    **   xtype                       The class of the conversion.
+    **   infop                       Pointer to the appropriate info struct.
+    */
+    switch( xtype ){
+      case etPOINTER:
+        flag_longlong = sizeof(char*)==sizeof(int64_t);
+        flag_long = sizeof(char*)==sizeof(long int);
+        /* Fall through into the next case */
+      case etRADIX:
+        if( infop-&gt;flags &amp; FLAG_SIGNED ){
+          int64_t v;
+          if( flag_longlong )   v = va_arg(ap,int64_t);
+          else if( flag_long )  v = va_arg(ap,long int);
+          else                  v = va_arg(ap,int);
+          if( v&lt;0 ){
+            longvalue = -v;
+            prefix = '-';
+          }else{
+            longvalue = v;
+            if( flag_plussign )        prefix = '+';
+            else if( flag_blanksign )  prefix = ' ';
+            else                       prefix = 0;
+          }
+        }else{
+          if( flag_longlong )   longvalue = va_arg(ap,uint64_t);
+          else if( flag_long )  longvalue = va_arg(ap,unsigned long int);
+          else                  longvalue = va_arg(ap,unsigned int);
+          prefix = 0;
+        }
+        if( longvalue==0 ) flag_alternateform = 0;
+        if( flag_zeropad &amp;&amp; precision&lt;width-(prefix!=0) ){
+          precision = width-(prefix!=0);
+        }
+        bufpt = &amp;buf[etBUFSIZE-1];
+        {
+          register const char *cset;      /* Use registers for speed */
+          register int base;
+          cset = &amp;aDigits[infop-&gt;charset];
+          base = infop-&gt;base;
+          do{                                           /* Convert to ascii */
+            *(--bufpt) = cset[longvalue%base];
+            longvalue = longvalue/base;
+          }while( longvalue&gt;0 );
+        }
+        length = &amp;buf[etBUFSIZE-1]-bufpt;
+        for(idx=precision-length; idx&gt;0; idx--){
+          *(--bufpt) = '0';                             /* Zero pad */
+        }
+        if( prefix ) *(--bufpt) = prefix;               /* Add sign */
+        if( flag_alternateform &amp;&amp; infop-&gt;prefix ){      /* Add &quot;0&quot; or &quot;0x&quot; */
+          const char *pre;
+          char x;
+          pre = &amp;aPrefix[infop-&gt;prefix];
+          if( *bufpt!=pre[0] ){
+            for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
+          }
+        }
+        length = &amp;buf[etBUFSIZE-1]-bufpt;
+        break;
+      case etFLOAT:
+      case etEXP:
+      case etGENERIC:
+        realvalue = va_arg(ap,double);
+#ifndef SWITCH_OMIT_FLOATING_POINT
+        if( precision&lt;0 ) precision = 6;         /* Set default precision */
+        if( precision&gt;etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
+        if( realvalue&lt;0.0 ){
+          realvalue = -realvalue;
+          prefix = '-';
+        }else{
+          if( flag_plussign )          prefix = '+';
+          else if( flag_blanksign )    prefix = ' ';
+          else                         prefix = 0;
+        }
+        if( xtype==etGENERIC &amp;&amp; precision&gt;0 ) precision--;
+#if 0
+        /* Rounding works like BSD when the constant 0.4999 is used.  Wierd! */
+        for(idx=precision, rounder=0.4999; idx&gt;0; idx--, rounder*=0.1);
+#else
+        /* It makes more sense to use 0.5 */
+        for(idx=precision, rounder=0.5; idx&gt;0; idx--, rounder*=0.1){}
+#endif
+        if( xtype==etFLOAT ) realvalue += rounder;
+        /* Normalize realvalue to within 10.0 &gt; realvalue &gt;= 1.0 */
+        exp = 0;
+        if( realvalue&gt;0.0 ){
+          while( realvalue&gt;=1e32 &amp;&amp; exp&lt;=350 ){ realvalue *= 1e-32; exp+=32; }
+          while( realvalue&gt;=1e8 &amp;&amp; exp&lt;=350 ){ realvalue *= 1e-8; exp+=8; }
+          while( realvalue&gt;=10.0 &amp;&amp; exp&lt;=350 ){ realvalue *= 0.1; exp++; }
+          while( realvalue&lt;1e-8 &amp;&amp; exp&gt;=-350 ){ realvalue *= 1e8; exp-=8; }
+          while( realvalue&lt;1.0 &amp;&amp; exp&gt;=-350 ){ realvalue *= 10.0; exp--; }
+          if( exp&gt;350 || exp&lt;-350 ){
+            bufpt = &quot;NaN&quot;;
+            length = 3;
+            break;
+          }
+        }
+        bufpt = buf;
+        /*
+        ** If the field type is etGENERIC, then convert to either etEXP
+        ** or etFLOAT, as appropriate.
+        */
+        flag_exp = xtype==etEXP;
+        if( xtype!=etFLOAT ){
+          realvalue += rounder;
+          if( realvalue&gt;=10.0 ){ realvalue *= 0.1; exp++; }
+        }
+        if( xtype==etGENERIC ){
+          flag_rtz = !flag_alternateform;
+          if( exp&lt;-4 || exp&gt;precision ){
+            xtype = etEXP;
+          }else{
+            precision = precision - exp;
+            xtype = etFLOAT;
+          }
+        }else{
+          flag_rtz = 0;
+        }
+        if( xtype==etEXP ){
+          e2 = 0;
+        }else{
+          e2 = exp;
+        }
+        nsd = 0;
+        flag_dp = (precision&gt;0) | flag_alternateform | flag_altform2;
+        /* The sign in front of the number */
+        if( prefix ){
+          *(bufpt++) = prefix;
+        }
+        /* Digits prior to the decimal point */
+        if( e2&lt;0 ){
+          *(bufpt++) = '0';
+        }else{
+          for(; e2&gt;=0; e2--){
+            *(bufpt++) = et_getdigit(&amp;realvalue,&amp;nsd);
+          }
+        }
+        /* The decimal point */
+        if( flag_dp ){
+          *(bufpt++) = '.';
+        }
+        /* &quot;0&quot; digits after the decimal point but before the first
+        ** significant digit of the number */
+        for(e2++; e2&lt;0 &amp;&amp; precision&gt;0; precision--, e2++){
+          *(bufpt++) = '0';
+        }
+        /* Significant digits after the decimal point */
+        while( (precision--)&gt;0 ){
+          *(bufpt++) = et_getdigit(&amp;realvalue,&amp;nsd);
+        }
+        /* Remove trailing zeros and the &quot;.&quot; if no digits follow the &quot;.&quot; */
+        if( flag_rtz &amp;&amp; flag_dp ){
+          while( bufpt[-1]=='0' ) *(--bufpt) = 0;
+          assert( bufpt&gt;buf );
+          if( bufpt[-1]=='.' ){
+            if( flag_altform2 ){
+              *(bufpt++) = '0';
+            }else{
+              *(--bufpt) = 0;
+            }
+          }
+        }
+        /* Add the &quot;eNNN&quot; suffix */
+        if( flag_exp || (xtype==etEXP &amp;&amp; exp) ){
+          *(bufpt++) = aDigits[infop-&gt;charset];
+          if( exp&lt;0 ){
+            *(bufpt++) = '-'; exp = -exp;
+          }else{
+            *(bufpt++) = '+';
+          }
+          if( exp&gt;=100 ){
+            *(bufpt++) = (exp/100)+'0';                /* 100's digit */
+            exp %= 100;
+          }
+          *(bufpt++) = exp/10+'0';                     /* 10's digit */
+          *(bufpt++) = exp%10+'0';                     /* 1's digit */
+        }
+        *bufpt = 0;
+
+        /* The converted number is in buf[] and zero terminated. Output it.
+        ** Note that the number is in the usual order, not reversed as with
+        ** integer conversions. */
+        length = bufpt-buf;
+        bufpt = buf;
+
+        /* Special case:  Add leading zeros if the flag_zeropad flag is
+        ** set and we are not left justified */
+        if( flag_zeropad &amp;&amp; !flag_leftjustify &amp;&amp; length &lt; width){
+          int i;
+          int nPad = width - length;
+          for(i=width; i&gt;=nPad; i--){
+            bufpt[i] = bufpt[i-nPad];
+          }
+          i = prefix!=0;
+          while( nPad-- ) bufpt[i++] = '0';
+          length = width;
+        }
+#endif
+        break;
+      case etSIZE:
+        *(va_arg(ap,int*)) = count;
+        length = width = 0;
+        break;
+      case etPERCENT:
+        buf[0] = '%';
+        bufpt = buf;
+        length = 1;
+        break;
+      case etCHARLIT:
+      case etCHARX:
+        c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
+        if( precision&gt;=0 ){
+          for(idx=1; idx&lt;precision; idx++) buf[idx] = c;
+          length = precision;
+        }else{
+          length =1;
+        }
+        bufpt = buf;
+        break;
+      case etSTRING:
+      case etDYNSTRING:
+        bufpt = va_arg(ap,char*);
+        if( bufpt==0 ){
+          bufpt = &quot;&quot;;
+        }else if( xtype==etDYNSTRING ){
+          zExtra = bufpt;
+        }
+        length = strlen(bufpt);
+        if( precision&gt;=0 &amp;&amp; precision&lt;length ) length = precision;
+        break;
+      case etSQLESCAPE:
+      case etSQLESCAPE2:
+      case etSQLESCAPE3: {
+        int i, j, n, ch, isnull;
+        int needQuote;
+        char *escarg = va_arg(ap,char*);
+        isnull = escarg==0;
+        if( isnull ) escarg = (xtype==etSQLESCAPE2 ? &quot;NULL&quot; : &quot;(NULL)&quot;);
+        for(i=n=0; (ch=escarg[i])!=0; i++){
+                        if( ch=='\'' || (xtype==etSQLESCAPE3 &amp;&amp; ch=='\\')) n++;
+        }
+        needQuote = !isnull &amp;&amp; xtype==etSQLESCAPE2;
+        n += i + 1 + needQuote*2;
+        if( n&gt;etBUFSIZE ){
+          bufpt = zExtra = malloc( n );
+          if( bufpt==0 ) return -1;
+        }else{
+          bufpt = buf;
+        }
+        j = 0;
+        if( needQuote ) bufpt[j++] = '\'';
+        for(i=0; (ch=escarg[i])!=0; i++){
+          bufpt[j++] = ch;
+          if( ch=='\'' || ( xtype==etSQLESCAPE3 &amp;&amp; ch=='\\')) bufpt[j++] = ch;
+        }
+        if( needQuote ) bufpt[j++] = '\'';
+        bufpt[j] = 0;
+        length = j;
+        /* The precision is ignored on %q and %Q */
+        /* if( precision&gt;=0 &amp;&amp; precision&lt;length ) length = precision; */
+        break;
+      }
+#ifdef __UNSUPPORTED__
+      case etTOKEN: {
+        Token *pToken = va_arg(ap, Token*);
+        if( pToken &amp;&amp; pToken-&gt;z ){
+          (*func)(arg, (char*)pToken-&gt;z, pToken-&gt;n);
+        }
+        length = width = 0;
+        break;
+      }
+      case etSRCLIST: {
+        SrcList *pSrc = va_arg(ap, SrcList*);
+        int k = va_arg(ap, int);
+        struct SrcList_item *pItem = &amp;pSrc-&gt;a[k];
+        assert( k&gt;=0 &amp;&amp; k&lt;pSrc-&gt;nSrc );
+        if( pItem-&gt;zDatabase &amp;&amp; pItem-&gt;zDatabase[0] ){
+          (*func)(arg, pItem-&gt;zDatabase, strlen(pItem-&gt;zDatabase));
+          (*func)(arg, &quot;.&quot;, 1);
+        }
+        (*func)(arg, pItem-&gt;zName, strlen(pItem-&gt;zName));
+        length = width = 0;
+        break;
+      }
+#endif
+    }/* End switch over the format type */
+    /*
+    ** The text of the conversion is pointed to by &quot;bufpt&quot; and is
+    ** &quot;length&quot; characters long.  The field width is &quot;width&quot;.  Do
+    ** the output.
+    */
+    if( !flag_leftjustify ){
+      register int nspace;
+      nspace = width-length;
+      if( nspace&gt;0 ){
+        count += nspace;
+        while( nspace&gt;=etSPACESIZE ){
+          (*func)(arg,spaces,etSPACESIZE);
+          nspace -= etSPACESIZE;
+        }
+        if( nspace&gt;0 ) (*func)(arg,spaces,nspace);
+      }
+    }
+    if( length&gt;0 ){
+      (*func)(arg,bufpt,length);
+      count += length;
+    }
+    if( flag_leftjustify ){
+      register int nspace;
+      nspace = width-length;
+      if( nspace&gt;0 ){
+        count += nspace;
+        while( nspace&gt;=etSPACESIZE ){
+          (*func)(arg,spaces,etSPACESIZE);
+          nspace -= etSPACESIZE;
+        }
+        if( nspace&gt;0 ) (*func)(arg,spaces,nspace);
+      }
+    }
+    if( zExtra ){
+      free(zExtra);
+    }
+  }/* End for loop over the format string */
+  return errorflag ? -1 : count;
+} /* End of function */
+
+
+/* This structure is used to store state information about the
+** write to memory that is currently in progress.
+*/
+struct sgMprintf {
+  char *zBase;     /* A base allocation */
+  char *zText;     /* The string collected so far */
+  int  nChar;      /* Length of the string so far */
+  int  nTotal;     /* Output size if unconstrained */
+  int  nAlloc;     /* Amount of space allocated in zText */
+  void *(*xRealloc)(void*,int);  /* Function used to realloc memory */
+};
+
+/*
+** This function implements the callback from vxprintf.
+**
+** This routine add nNewChar characters of text in zNewText to
+** the sgMprintf structure pointed to by &quot;arg&quot;.
+*/
+static void mout(void *arg, const char *zNewText, int nNewChar){
+  struct sgMprintf *pM = (struct sgMprintf*)arg;
+  pM-&gt;nTotal += nNewChar;
+  if( pM-&gt;nChar + nNewChar + 1 &gt; pM-&gt;nAlloc ){
+    if( pM-&gt;xRealloc==0 ){
+      nNewChar =  pM-&gt;nAlloc - pM-&gt;nChar - 1;
+    }else{
+      pM-&gt;nAlloc = pM-&gt;nChar + nNewChar*2 + 1;
+      if( pM-&gt;zText==pM-&gt;zBase ){
+        pM-&gt;zText = pM-&gt;xRealloc(0, pM-&gt;nAlloc);
+        if( pM-&gt;zText &amp;&amp; pM-&gt;nChar ){
+          memcpy(pM-&gt;zText, pM-&gt;zBase, pM-&gt;nChar);
+        }
+      }else{
+        char *zNew;
+        zNew = pM-&gt;xRealloc(pM-&gt;zText, pM-&gt;nAlloc);
+        if( zNew ){
+          pM-&gt;zText = zNew;
+        }
+      }
+    }
+  }
+  if( pM-&gt;zText ){
+    if( nNewChar&gt;0 ){
+      memcpy(&amp;pM-&gt;zText[pM-&gt;nChar], zNewText, nNewChar);
+      pM-&gt;nChar += nNewChar;
+    }
+    pM-&gt;zText[pM-&gt;nChar] = 0;
+  }
+}
+
+/*
+** This routine is a wrapper around xprintf() that invokes mout() as
+** the consumer.
+*/
+static char *base_vprintf(
+  void *(*xRealloc)(void*,int),   /* Routine to realloc memory. May be NULL */
+  int useInternal,                /* Use internal %-conversions if true */
+  char *zInitBuf,                 /* Initially write here, before mallocing */
+  int nInitBuf,                   /* Size of zInitBuf[] */
+  const char *zFormat,            /* format string */
+  va_list ap                      /* arguments */
+){
+  struct sgMprintf sM;
+  sM.zBase = sM.zText = zInitBuf;
+  sM.nChar = sM.nTotal = 0;
+  sM.nAlloc = nInitBuf;
+  sM.xRealloc = xRealloc;
+  vxprintf(mout, &amp;sM, useInternal, zFormat, ap);
+  if( xRealloc ){
+    if( sM.zText==sM.zBase ){
+      sM.zText = xRealloc(0, sM.nChar+1);
+      if( sM.zText ){
+        memcpy(sM.zText, sM.zBase, sM.nChar+1);
+      }
+    }else if( sM.nAlloc&gt;sM.nChar+10 ){
+      char *zNew = xRealloc(sM.zText, sM.nChar+1);
+      if( zNew ){
+        sM.zText = zNew;
+      }
+    }
+  }
+  return sM.zText;
+}
+
+/*
+** Realloc that is a real function, not a macro.
+*/
+static void *printf_realloc(void *old, int size)
+{
+  return realloc(old,size);
+}
+
+/*
+** Print into memory. Use the internal %-conversion extensions.
+*/
+SWITCH_DECLARE(char *) switch_vmprintf(const char *zFormat, va_list ap)
+{
+  char zBase[SWITCH_PRINT_BUF_SIZE];
+  return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
+}
+
+/*
+** Print into memory. Use the internal %-conversion extensions.
+*/
+SWITCH_DECLARE(char *) switch_mprintf(const char *zFormat, ...)
+{
+  va_list ap;
+  char *z;
+  char zBase[SWITCH_PRINT_BUF_SIZE];
+  va_start(ap, zFormat);
+  z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
+  va_end(ap);
+  return z;
+}
+
+#ifdef __UNUSED__
+/*
+** Print into memory. Omit the internal %-conversion extensions.
+*/
+SWITCH_DECLARE(char *) switch_vmprintf(const char *zFormat, va_list ap)
+{
+  char zBase[SWITCH_PRINT_BUF_SIZE];
+  return base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
+}
+
+/*
+** Print into memory.  Omit the internal %-conversion extensions.
+*/
+SWITCH_DECLARE(char *) switch_mprintf(const char *zFormat, ...)
+{
+  va_list ap;
+  char *z;
+  char zBase[SWITCH_PRINT_BUF_SIZE];
+  va_start(ap, zFormat);
+  z = base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
+  va_end(ap);
+  return z;
+}
+
+/*
+** sqlite3_snprintf() works like snprintf() except that it ignores the
+** current locale settings.  This is important for SQLite because we
+** are not able to use a &quot;,&quot; as the decimal point in place of &quot;.&quot; as
+** specified by some locales.
+*/
+SWITCH_DECLARE(char *) switch_snprintf(int n, char *zBuf, const char *zFormat, ...)
+{
+  char *z;
+  va_list ap;
+
+  va_start(ap,zFormat);
+  z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
+  va_end(ap);
+  return z;
+}
+#endif
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>