Index: src/printf.c
==================================================================
--- src/printf.c
+++ src/printf.c
@@ -47,10 +47,11 @@
 #define etFOSSILIZE  19 /* The fossil header encoding format. */
 #define etPATH       20 /* Path type */
 #define etWIKISTR    21 /* Wiki text rendered from a char*: %w */
 #define etWIKIBLOB   22 /* Wiki text rendered from a Blob*: %W */
 #define etSTRINGID   23 /* String with length limit for a UUID prefix: %S */
+#define etCOMMA      24 /* Like %d but with commas: %D */
 
 
 /*
 ** An "etByte" is an 8-bit unsigned value.
 */
@@ -90,10 +91,11 @@
   {  'z',  0, 6, etDYNSTRING,  0,  0 },
   {  'q',  0, 4, etSQLESCAPE,  0,  0 },
   {  'Q',  0, 4, etSQLESCAPE2, 0,  0 },
   {  'b',  0, 2, etBLOB,       0,  0 },
   {  'B',  0, 2, etBLOBSQL,    0,  0 },
+  {  'D', 10, 2, etCOMMA,      0,  0 },
   {  'w',  0, 2, etWIKISTR,    0,  0 },
   {  'W',  0, 2, etWIKIBLOB,   0,  0 },
   {  'h',  0, 4, etHTMLIZE,    0,  0 },
   {  't',  0, 4, etHTTPIZE,    0,  0 },  /* "/" -> "%2F" */
   {  'T',  0, 4, etURLIZE,     0,  0 },  /* "/" unchanged */
@@ -241,11 +243,11 @@
       blob_append(pBlob,"%",1);
       count++;
       break;
     }
     /* Find out what flags are present */
-    flag_leftjustify = flag_plussign = flag_blanksign = 
+    flag_leftjustify = flag_plussign = flag_blanksign =
      flag_alternateform = flag_altform2 = flag_zeropad = 0;
     done = 0;
     do{
       switch( c ){
         case '-':   flag_leftjustify = 1;     break;
@@ -347,10 +349,11 @@
       case etPOINTER:
         flag_longlong = sizeof(char*)==sizeof(i64);
         flag_long = sizeof(char*)==sizeof(long int);
         /* Fall through into the next case */
       case etRADIX:
+      case etCOMMA:
         if( infop->flags & FLAG_SIGNED ){
           i64 v;
           if( flag_longlong )   v = va_arg(ap,i64);
           else if( flag_long )  v = va_arg(ap,long int);
           else                  v = va_arg(ap,int);
@@ -387,19 +390,29 @@
         length = &buf[etBUFSIZE-1]-bufpt;
         for(idx=precision-length; idx>0; idx--){
           *(--bufpt) = '0';                             /* Zero pad */
         }
         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
+        length = &buf[etBUFSIZE-1]-bufpt;
+        if( xtype==etCOMMA && length>=4 ){
+          int i, j, k;
+          int nComma = (length-1)/3;
+          bufpt -= nComma;
+          for(i=k=0, j=nComma; i<j; i++, j++, k++){
+            bufpt[i] = bufpt[j];
+            if( (length-k)%3==1 ) bufpt[++i] = ',';
+          }
+          length += nComma;
+        }
         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);

Index: src/stat.c
==================================================================
--- src/stat.c
+++ src/stat.c
@@ -31,27 +31,28 @@
   i64 t, fsize;
   int n, m;
   int szMax, szAvg;
   const char *zDb;
   int brief;
-  char zBuf[100];
+  char *z;
+  char zBuf[200];
 
   login_check_credentials();
   if( !g.perm.Read ){ login_needed(); return; }
   brief = P("brief")!=0;
   style_header("Repository Statistics");
   @ <table class="label-value">
   @ <tr><th>Repository&nbsp;Size:</th><td>
   fsize = file_size(g.zRepositoryName);
-  sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", fsize);
-  @ %s(zBuf) bytes
+  z = mprintf("%llD", fsize);
+  @ %z(z) bytes
   @ </td></tr>
   if( !brief ){
     @ <tr><th>Number&nbsp;Of&nbsp;Artifacts:</th><td>
     n = db_int(0, "SELECT count(*) FROM blob");
     m = db_int(0, "SELECT count(*) FROM delta");
-    @ %d(n) (stored as %d(n-m) full text and %d(m) delta blobs)
+    @ %D(n) (stored as %D(n-m) full text and %D(m) delta blobs)
     @ </td></tr>
     if( n>0 ){
       int a, b;
       Stmt q;
       @ <tr><th>Uncompressed&nbsp;Artifact&nbsp;Size:</th><td>
@@ -60,12 +61,12 @@
       db_step(&q);
       t = db_column_int64(&q, 0);
       szAvg = db_column_int(&q, 1);
       szMax = db_column_int(&q, 2);
       db_finalize(&q);
-      sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", t);
-      @ %d(szAvg) bytes average, %d(szMax) bytes max, %s(zBuf) bytes total
+      z = mprintf("%llD", t);
+      @ %D(szAvg) bytes average, %D(szMax) bytes max, %z(z) bytes total
       @ </td></tr>
       @ <tr><th>Compression&nbsp;Ratio:</th><td>
       if( t/fsize < 5 ){
         b = 10;
         fsize /= 10;
@@ -76,31 +77,31 @@
       @ %d(a):%d(b)
       @ </td></tr>
     }
     @ <tr><th>Number&nbsp;Of&nbsp;Check-ins:</th><td>
     n = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/");
-    @ %d(n)
+    @ %D(n)
     @ </td></tr>
     @ <tr><th>Number&nbsp;Of&nbsp;Files:</th><td>
     n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
-    @ %d(n)
+    @ %D(n)
     @ </td></tr>
     @ <tr><th>Number&nbsp;Of&nbsp;Wiki&nbsp;Pages:</th><td>
     n = db_int(0, "SELECT count(*) FROM tag  /*scan*/"
                   " WHERE +tagname GLOB 'wiki-*'");
-    @ %d(n)
+    @ %D(n)
     @ </td></tr>
     @ <tr><th>Number&nbsp;Of&nbsp;Tickets:</th><td>
     n = db_int(0, "SELECT count(*) FROM tag  /*scan*/"
                   " WHERE +tagname GLOB 'tkt-*'");
-    @ %d(n)
+    @ %D(n)
     @ </td></tr>
   }
   @ <tr><th>Duration&nbsp;Of&nbsp;Project:</th><td>
   n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
                 " + 0.99");
-  @ %d(n) days
+  @ %D(n) days
   sqlite3_snprintf(sizeof(zBuf), zBuf, "%.2f", n/365.24);
   @ or approximately %s(zBuf) years
   @ </td></tr>
   @ <tr><th>Project&nbsp;ID:</th><td>%h(db_get("project-code",""))</td></tr>
   @ <tr><th>Server&nbsp;ID:</th><td>%h(db_get("server-code",""))</td></tr>