<!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 "switch_platform.h"
</span><span class="cx"> #include "switch_types.h"
</span><span class="cx"> #include "switch_apr.h"
</span><del>-
</del><ins>+#include "switch_mprintf.h"
</ins><span class="cx"> #include "switch_core_db.h"
</span><span class="cx"> #include "switch_dso.h"
</span><span class="cx"> #include "switch_regex.h"
</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 "sprintf()" 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 "%q" 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 = "It's a happy day!";
+ *
+ * We can use this text in an SQL statement as follows:
+ *
+ * char *z = switch_core_db_mprintf("INSERT INTO TABLES('%q')", 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("add sofia profile");
</span><span class="cx">         switch_console_set_complete("add sofia profile restart all");
</span><span class="cx">
</span><ins>+        switch_console_set_complete("add sofia profile _any_ start reloadxml");
+        switch_console_set_complete("add sofia profile _any_ stop reloadxml");
+        switch_console_set_complete("add sofia profile _any_ rescan reloadxml");
+        switch_console_set_complete("add sofia profile _any_ restart reloadxml");
+
+        switch_console_set_complete("add sofia profile _any_ flush_inbound_reg");
+        switch_console_set_complete("add sofia profile _any_ register");
+        switch_console_set_complete("add sofia profile _any_ killgw");
+        switch_console_set_complete("add sofia profile _any_ siptrace on");
+        switch_console_set_complete("add sofia profile _any_ siptrace off");
+
+
</ins><span class="cx">         SWITCH_ADD_API(api_interface, "sofia_contact", "Sofia Contacts", sofia_contact_function, "[profile/]<user>@<domain>");
</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("del sofia");
+
</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] = "";
</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), "add sofia profile %s", profile->name);
+        switch_console_set_complete(cbuf);
+
+
</ins><span class="cx">         while (mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING) && sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
</span><span class="cx">                 su_root_step(profile->s_root, 1000);
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+        switch_snprintf(cbuf, sizeof(cbuf), "del sofia profile %s", profile->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("sofia_profile_name", profile->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] = "";
</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), "add sofia profile %s", 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] = "";
+        
</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, &var, NULL, &val);
</span><span class="cx">                         if ((pptr = (sofia_profile_t *) val) && pptr == profile) {
</span><span class="cx">                                 aliases[i++] = strdup((char *) var);
</span><ins>+                                switch_snprintf(cbuf, sizeof(cbuf), "del sofia profile %s", 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(&data, fmt, ap);
</del><ins>+        //ret = switch_vasprintf(&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(&db);
</span><span class="cx">
</span><del>-        sql = switch_mprintf("select command from aliases where alias='%q'", cmd);
</del><span class="cx">
</span><ins>+        if (db->type == SCDB_TYPE_CORE_DB) {
+                sql = switch_mprintf("select command from aliases where alias='%q'", cmd);
+        } else {
+                sql = switch_mprintf("select command from aliases where alias='%w'", cmd);
+        }
+
</ins><span class="cx">         switch_cache_db_execute_sql_callback(db, sql, alias_callback, &r, &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("select command from aliases where alias='%q %q'", cmd, arg);
</del><ins>+                if (db->type == SCDB_TYPE_CORE_DB) {
+                        sql = switch_mprintf("select command from aliases where alias='%q %q'", cmd, arg);
+                } else {
+                        sql = switch_mprintf("select command from aliases where alias='%w %w'", cmd, arg);
+                }
</ins><span class="cx">
</span><span class="cx">                 switch_cache_db_execute_sql_callback(db, sql, alias_callback, &r, &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->out, "[%20s]\t", target);
</del><ins>+        if (!zstr(target)) {
+                fprintf(h->out, "[%20s]\t", target);
+                switch_copy_string(h->last, target, sizeof(h->last));
+                h->hits++;
+        }
+        
+        x = strlen(h->last);
+        y = strlen(h->partial);
</ins><span class="cx">
</span><del>-        switch_copy_string(h->last, target, sizeof(h->last));
</del><ins>+        if (h->hits > 1) {
+                for(i = 0; i < x && i < y; i++) {
+                        if (h->last[i] != h->partial[i]) {
+                                h->partial[i] = '\0';
+                                break;
+                        }
+                }        
+        } else if (h->hits == 1) {
+                switch_copy_string(h->partial, target, sizeof(h->last));
+        }
</ins><span class="cx">
</span><span class="cx">         if (!zstr(target)) {
</span><del>-                if ((++h->hits % 4) == 0) {
</del><ins>+                if ((h->hits % 4) == 0) {
</ins><span class="cx">                         fprintf(h->out, "\n");
</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 < argc; x++) {
-                        stream.write_function(&stream, "(a%d = '' or a%d like '%s%%')%s", x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? "" : " and ");
</del><ins>+                for (x = 0; x < argc && x < 11; x++) {
+                        if (h.words + 1 > argc) {
+                                if (db->type == SCDB_TYPE_CORE_DB) {
+                                        stream.write_function(&stream, "(a%d = '' or a%d = '%q')%q", x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? "" : " and ");
+                                } else {
+                                        stream.write_function(&stream, "(a%d = '' or a%d = '%w')%w", x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? "" : " and ");
+                                }
+                        } else {
+                                if (db->type == SCDB_TYPE_CORE_DB) {
+                                        stream.write_function(&stream, "(a%d = '' or a%d like '%q%%')%q", x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? "" : " and ");
+                                } else {
+                                        stream.write_function(&stream, "(a%d = '' or a%d like '%w%%')%w", x + 1, x + 1, switch_str_nil(argv[x]), x == argc - 1 ? "" : " and ");
+                                }
+                        }
</ins><span class="cx">                 }
</span><span class="cx">
</span><span class="cx">                 stream.write_function(&stream, " and hostname='%s'", switch_core_get_variable("hostname"));
</span><span class="lines">@@ -624,9 +667,13 @@
</span><span class="cx">
</span><span class="cx">         fprintf(h.out, "\n\n");
</span><span class="cx">
</span><del>-        if (h.hits == 1) {
</del><ins>+        if (h.hits == 1 && !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, " ");
+        } else if (h.hits > 1 && !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(&db);
</span><del>-                        
</del><ins>+
</ins><span class="cx">                         if (!strcasecmp(argv[0], "stickyadd")) {
</span><span class="cx">                                 mystream.write_function(&mystream, "insert into complete values (1,");
</span><span class="cx">                                 for (x = 0; x < 10; x++) {
</span><del>-                                        mystream.write_function(&mystream, "'%s', ", switch_str_nil(argv[x + 1]));
</del><ins>+                                        if (argv[x + 1] && !strcasecmp(argv[x + 1], "_any_")) {
+                                                mystream.write_function(&mystream, "%s", "'', ");
+                                        } else {
+                                                if (db->type == SCDB_TYPE_CORE_DB) {
+                                                        mystream.write_function(&mystream, "'%q', ", switch_str_nil(argv[x + 1]));
+                                                } else {
+                                                        mystream.write_function(&mystream, "'%w', ", switch_str_nil(argv[x + 1]));
+                                                }
+                                        }
</ins><span class="cx">                                 }
</span><span class="cx">                                 mystream.write_function(&mystream, " '%s')", switch_core_get_variable("hostname"));
</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], "add")) {
</span><span class="cx">                                 mystream.write_function(&mystream, "insert into complete values (0,");
</span><span class="cx">                                 for (x = 0; x < 10; x++) {
</span><del>-                                        mystream.write_function(&mystream, "'%s', ", switch_str_nil(argv[x + 1]));
</del><ins>+                                        if (argv[x + 1] && !strcasecmp(argv[x + 1], "_any_")) {
+                                                mystream.write_function(&mystream, "%s", "'', ");
+                                        } else {
+                                                if (db->type == SCDB_TYPE_CORE_DB) {
+                                                        mystream.write_function(&mystream, "'%q', ", switch_str_nil(argv[x + 1]));
+                                                } else {
+                                                        mystream.write_function(&mystream, "'%w', ", switch_str_nil(argv[x + 1]));
+                                                }
+                                        }
</ins><span class="cx">                                 }
</span><span class="cx">                                 mystream.write_function(&mystream, " '%s')", switch_core_get_variable("hostname"));
</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], "del")) {
</span><span class="lines">@@ -679,13 +743,18 @@
</span><span class="cx">                                 } else {
</span><span class="cx">                                         mystream.write_function(&mystream, "delete from complete where ");
</span><span class="cx">                                         for (x = 0; x < argc - 1; x++) {
</span><del>-                                                mystream.write_function(&mystream, "a%d = '%s'%s", x + 1, switch_str_nil(argv[x + 1]), x == argc - 2 ? "" : " and ");
</del><ins>+                                                if (db->type == SCDB_TYPE_CORE_DB) {
+                                                        mystream.write_function(&mystream, "a%d = '%q'%q", x + 1, switch_str_nil(argv[x + 1]), x == argc - 2 ? "" : " and ");
+                                                } else {
+                                                        mystream.write_function(&mystream, "a%d = '%w'%w", x + 1, switch_str_nil(argv[x + 1]), x == argc - 2 ? "" : " and ");
+                                                }
</ins><span class="cx">                                         }
</span><span class="cx">                                         mystream.write_function(&mystream, " and hostname='%s'", switch_core_get_variable("hostname"));
</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(&db);
</span><span class="cx">                 }
</span><span class="lines">@@ -715,16 +784,26 @@
</span><span class="cx">                                 sql = switch_mprintf("delete from aliases where alias='%q' and hostname='%q'", argv[1], switch_core_get_variable("hostname"));
</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("insert into aliases (sticky, alias, command, hostname) values (1, '%q','%q','%q')",
-                                                                         argv[1], argv[2], switch_core_get_variable("hostname"));
</del><ins>+                                if (db->type == SCDB_TYPE_CORE_DB) {
+                                        sql = switch_mprintf("insert into aliases (sticky, alias, command, hostname) values (1, '%q','%q','%q')",
+                                                                                 argv[1], argv[2], switch_core_get_variable("hostname"));
+                                } else {
+                                        sql = switch_mprintf("insert into aliases (sticky, alias, command, hostname) values (1, '%w','%w','%w')",
+                                                                                 argv[1], argv[2], switch_core_get_variable("hostname"));
+                                }
</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], "add") && argc == 3) {
</span><span class="cx">                                 sql = switch_mprintf("delete from aliases where alias='%q' and hostname='%q'", argv[1], switch_core_get_variable("hostname"));
</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("insert into aliases (sticky, alias, command, hostname) values (0, '%q','%q','%q')",
-                                                                         argv[1], argv[2], switch_core_get_variable("hostname"));
</del><ins>+                                if (db->type == SCDB_TYPE_CORE_DB) {
+                                        sql = switch_mprintf("insert into aliases (sticky, alias, command, hostname) values (0, '%q','%q','%q')",
+                                                                                 argv[1], argv[2], switch_core_get_variable("hostname"));
+                                } else {
+                                        sql = switch_mprintf("insert into aliases (sticky, alias, command, hostname) values (0, '%w','%w','%w')",
+                                                                                 argv[1], argv[2], switch_core_get_variable("hostname"));
+                                }
</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], "del") && 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 "printf" 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 "enhancements" have been backed
+** out so that the functionality is now the same as standard printf().
+**
+**************************************************************************
+**
+** The following modules is an enhanced replacement for the "printf" subroutines
+** found in the standard C library. The following enhancements are
+** supported:
+**
+** + Additional functions. The standard set of "printf" 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 "=" flag (similar to "-") 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("%.78'-") prints 78 minus
+** signs, the same as printf("%.78c",'-').
+**
+** + 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_ -> SWITCH_,
+ * renamed visible functions to switch_*
+ * disabled functions without extra conversion specifiers
+ */
+
+#include <switch.h>
+
+#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 "etByte" is an 8-bit unsigned value.
+*/
+typedef unsigned char etByte;
+
+/*
+** Each builtin conversion character (ex: the 'd' in "%d") 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[] = "0123456789ABCDEF0123456789abcdef";
+static const char aPrefix[] = "-x0\000X0";
+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
+/*
+** "*val" is a double such that 0.1 <= *val < 10.0
+** Return the ascii code for the leading digit of *val, then
+** multiply "*val" 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)++ >= 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 "arg" 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 "func". 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 "func". 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 "-" flag is present */
+ etByte flag_plussign; /* True if "+" flag is present */
+ etByte flag_blanksign; /* True if " " flag is present */
+ etByte flag_alternateform; /* True if "#" flag is present */
+ etByte flag_altform2; /* True if "!" flag is present */
+ etByte flag_zeropad; /* True if field width constant starts with zero */
+ etByte flag_long; /* True if "l" flag is present */
+ etByte flag_longlong; /* True if the "ll" 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. "+" or "-" or " " 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[] =
+ " ";
+#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,"",0);
+ count = length = 0;
+ bufpt = 0;
+ for(; (c=(*fmt))!=0; ++fmt){
+ if( c!='%' ){
+ int amt;
+ bufpt = (char *)fmt;
+ amt = 1;
+ while( (c=(*++fmt))!='%' && c!=0 ) amt++;
+ (*func)(arg,bufpt,amt);
+ count += amt;
+ if( c==0 ) break;
+ }
+ if( (c=(*++fmt))==0 ){
+ errorflag = 1;
+ (*func)(arg,"%",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 && (c=(*++fmt))!=0 );
+ /* Get the field width */
+ width = 0;
+ if( c=='*' ){
+ width = va_arg(ap,int);
+ if( width<0 ){
+ flag_leftjustify = 1;
+ width = -width;
+ }
+ c = *++fmt;
+ }else{
+ while( c>='0' && c<='9' ){
+ width = width*10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ if( width > etBUFSIZE-10 ){
+ width = etBUFSIZE-10;
+ }
+ /* Get the precision */
+ if( c=='.' ){
+ precision = 0;
+ c = *++fmt;
+ if( c=='*' ){
+ precision = va_arg(ap,int);
+ if( precision<0 ) precision = -precision;
+ c = *++fmt;
+ }else{
+ while( c>='0' && c<='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<etNINFO; idx++){
+ if( c==fmtinfo[idx].fmttype ){
+ infop = &fmtinfo[idx];
+ if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
+ xtype = infop->type;
+ }else{
+ return -1;
+ }
+ break;
+ }
+ }
+ zExtra = 0;
+ if( infop==0 ){
+ return -1;
+ }
+
+
+ /* Limit the precision to prevent overflowing buf[] during conversion */
+ if( precision>etBUFSIZE-40 && (infop->flags & 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->flags & 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<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 && precision<width-(prefix!=0) ){
+ precision = width-(prefix!=0);
+ }
+ bufpt = &buf[etBUFSIZE-1];
+ {
+ register const char *cset; /* Use registers for speed */
+ register int base;
+ cset = &aDigits[infop->charset];
+ base = infop->base;
+ do{ /* Convert to ascii */
+ *(--bufpt) = cset[longvalue%base];
+ longvalue = longvalue/base;
+ }while( longvalue>0 );
+ }
+ length = &buf[etBUFSIZE-1]-bufpt;
+ for(idx=precision-length; idx>0; idx--){
+ *(--bufpt) = '0'; /* Zero pad */
+ }
+ if( prefix ) *(--bufpt) = prefix; /* Add sign */
+ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
+ const char *pre;
+ char x;
+ pre = &aPrefix[infop->prefix];
+ if( *bufpt!=pre[0] ){
+ for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
+ }
+ }
+ length = &buf[etBUFSIZE-1]-bufpt;
+ break;
+ case etFLOAT:
+ case etEXP:
+ case etGENERIC:
+ realvalue = va_arg(ap,double);
+#ifndef SWITCH_OMIT_FLOATING_POINT
+ if( precision<0 ) precision = 6; /* Set default precision */
+ if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
+ if( realvalue<0.0 ){
+ realvalue = -realvalue;
+ prefix = '-';
+ }else{
+ if( flag_plussign ) prefix = '+';
+ else if( flag_blanksign ) prefix = ' ';
+ else prefix = 0;
+ }
+ if( xtype==etGENERIC && precision>0 ) precision--;
+#if 0
+ /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
+ for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
+#else
+ /* It makes more sense to use 0.5 */
+ for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
+#endif
+ if( xtype==etFLOAT ) realvalue += rounder;
+ /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
+ exp = 0;
+ if( realvalue>0.0 ){
+ while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
+ while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
+ while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
+ while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
+ while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
+ if( exp>350 || exp<-350 ){
+ bufpt = "NaN";
+ 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>=10.0 ){ realvalue *= 0.1; exp++; }
+ }
+ if( xtype==etGENERIC ){
+ flag_rtz = !flag_alternateform;
+ if( exp<-4 || exp>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>0) | flag_alternateform | flag_altform2;
+ /* The sign in front of the number */
+ if( prefix ){
+ *(bufpt++) = prefix;
+ }
+ /* Digits prior to the decimal point */
+ if( e2<0 ){
+ *(bufpt++) = '0';
+ }else{
+ for(; e2>=0; e2--){
+ *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ }
+ }
+ /* The decimal point */
+ if( flag_dp ){
+ *(bufpt++) = '.';
+ }
+ /* "0" digits after the decimal point but before the first
+ ** significant digit of the number */
+ for(e2++; e2<0 && precision>0; precision--, e2++){
+ *(bufpt++) = '0';
+ }
+ /* Significant digits after the decimal point */
+ while( (precision--)>0 ){
+ *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ }
+ /* Remove trailing zeros and the "." if no digits follow the "." */
+ if( flag_rtz && flag_dp ){
+ while( bufpt[-1]=='0' ) *(--bufpt) = 0;
+ assert( bufpt>buf );
+ if( bufpt[-1]=='.' ){
+ if( flag_altform2 ){
+ *(bufpt++) = '0';
+ }else{
+ *(--bufpt) = 0;
+ }
+ }
+ }
+ /* Add the "eNNN" suffix */
+ if( flag_exp || (xtype==etEXP && exp) ){
+ *(bufpt++) = aDigits[infop->charset];
+ if( exp<0 ){
+ *(bufpt++) = '-'; exp = -exp;
+ }else{
+ *(bufpt++) = '+';
+ }
+ if( exp>=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 && !flag_leftjustify && length < width){
+ int i;
+ int nPad = width - length;
+ for(i=width; i>=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>=0 ){
+ for(idx=1; idx<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 = "";
+ }else if( xtype==etDYNSTRING ){
+ zExtra = bufpt;
+ }
+ length = strlen(bufpt);
+ if( precision>=0 && precision<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 ? "NULL" : "(NULL)");
+ for(i=n=0; (ch=escarg[i])!=0; i++){
+                        if( ch=='\'' || (xtype==etSQLESCAPE3 && ch=='\\')) n++;
+ }
+ needQuote = !isnull && xtype==etSQLESCAPE2;
+ n += i + 1 + needQuote*2;
+ if( n>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 && ch=='\\')) bufpt[j++] = ch;
+ }
+ if( needQuote ) bufpt[j++] = '\'';
+ bufpt[j] = 0;
+ length = j;
+ /* The precision is ignored on %q and %Q */
+ /* if( precision>=0 && precision<length ) length = precision; */
+ break;
+ }
+#ifdef __UNSUPPORTED__
+ case etTOKEN: {
+ Token *pToken = va_arg(ap, Token*);
+ if( pToken && pToken->z ){
+ (*func)(arg, (char*)pToken->z, pToken->n);
+ }
+ length = width = 0;
+ break;
+ }
+ case etSRCLIST: {
+ SrcList *pSrc = va_arg(ap, SrcList*);
+ int k = va_arg(ap, int);
+ struct SrcList_item *pItem = &pSrc->a[k];
+ assert( k>=0 && k<pSrc->nSrc );
+ if( pItem->zDatabase && pItem->zDatabase[0] ){
+ (*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
+ (*func)(arg, ".", 1);
+ }
+ (*func)(arg, pItem->zName, strlen(pItem->zName));
+ length = width = 0;
+ break;
+ }
+#endif
+ }/* End switch over the format type */
+ /*
+ ** The text of the conversion is pointed to by "bufpt" and is
+ ** "length" characters long. The field width is "width". Do
+ ** the output.
+ */
+ if( !flag_leftjustify ){
+ register int nspace;
+ nspace = width-length;
+ if( nspace>0 ){
+ count += nspace;
+ while( nspace>=etSPACESIZE ){
+ (*func)(arg,spaces,etSPACESIZE);
+ nspace -= etSPACESIZE;
+ }
+ if( nspace>0 ) (*func)(arg,spaces,nspace);
+ }
+ }
+ if( length>0 ){
+ (*func)(arg,bufpt,length);
+ count += length;
+ }
+ if( flag_leftjustify ){
+ register int nspace;
+ nspace = width-length;
+ if( nspace>0 ){
+ count += nspace;
+ while( nspace>=etSPACESIZE ){
+ (*func)(arg,spaces,etSPACESIZE);
+ nspace -= etSPACESIZE;
+ }
+ if( nspace>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 "arg".
+*/
+static void mout(void *arg, const char *zNewText, int nNewChar){
+ struct sgMprintf *pM = (struct sgMprintf*)arg;
+ pM->nTotal += nNewChar;
+ if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
+ if( pM->xRealloc==0 ){
+ nNewChar = pM->nAlloc - pM->nChar - 1;
+ }else{
+ pM->nAlloc = pM->nChar + nNewChar*2 + 1;
+ if( pM->zText==pM->zBase ){
+ pM->zText = pM->xRealloc(0, pM->nAlloc);
+ if( pM->zText && pM->nChar ){
+ memcpy(pM->zText, pM->zBase, pM->nChar);
+ }
+ }else{
+ char *zNew;
+ zNew = pM->xRealloc(pM->zText, pM->nAlloc);
+ if( zNew ){
+ pM->zText = zNew;
+ }
+ }
+ }
+ }
+ if( pM->zText ){
+ if( nNewChar>0 ){
+ memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
+ pM->nChar += nNewChar;
+ }
+ pM->zText[pM->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, &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>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 "," as the decimal point in place of "." 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>