Please find as attached file another patch which:

   1. First test for a real terminal before spawning the pager command.
   2. No more paginate json command.

I see that most of you complain about this proposed feature.

It was only a proposition, if it is not accepted I won't care.

However, it would be possible to make both world happy:

   1. Those who don't like this feature simply don't set a pager-command
   setting.
   2. Those who want to use it set a pager-command setting.

And, IMHO adding or removing a '|' at the end of command names is not a
maintenance nightmare.


Note : provided patch can be applied against latest version of the trunk
([a0ce33c90b] at the time of this writing).
Index: src/allrepo.c
==================================================================
--- src/allrepo.c
+++ src/allrepo.c
@@ -418,15 +418,15 @@
     if( showLabel ){
       int len = (int)strlen(zFilename);
       int nStar = 80 - (len + 15);
       if( nStar<2 ) nStar = 1;
       fossil_print("%.13c %s %.*c\n", '*', zFilename, nStar, '*');
-      fflush(stdout);
+      fflush(our_stdout);
     }
     if( !quiet || dryRunFlag ){
       fossil_print("%s\n", zSyscmd);
-      fflush(stdout);
+      fflush(our_stdout);
     }
     rc = dryRunFlag ? 0 : fossil_system(zSyscmd);
     free(zSyscmd);
     free(zQFilename);
     if( stopOnError && rc ){

Index: src/blob.c
==================================================================
--- src/blob.c
+++ src/blob.c
@@ -859,17 +859,17 @@
   if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
     blob_is_init(pBlob);
 #if defined(_WIN32)
     nWrote = fossil_utf8_to_console(blob_buffer(pBlob), blob_size(pBlob), 0);
     if( nWrote>=0 ) return nWrote;
-    fflush(stdout);
-    _setmode(_fileno(stdout), _O_BINARY);
+    fflush(our_stdout);
+    _setmode(_fileno(our_stdout), _O_BINARY);
 #endif
-    nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), stdout);
+    nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), our_stdout);
 #if defined(_WIN32)
-    fflush(stdout);
-    _setmode(_fileno(stdout), _O_TEXT);
+    fflush(our_stdout);
+    _setmode(_fileno(our_stdout), _O_TEXT);
 #endif
   }else{
     file_mkfolder(zFilename, 1, 0);
     out = fossil_fopen(zFilename, "wb");
     if( out==0 ){

Index: src/branch.c
==================================================================
--- src/branch.c
+++ src/branch.c
@@ -261,11 +261,11 @@
   );
 }
 
 
 /*
-** COMMAND: branch
+** COMMAND: branch|
 **
 ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS?
 **
 ** Run various subcommands to manage branches of the open repository or
 ** of the repository identified by the -R or --repository option.

Index: src/bundle.c
==================================================================
--- src/bundle.c
+++ src/bundle.c
@@ -716,11 +716,11 @@
   }
   db_end_transaction(0);
 }
 
 /*
-** COMMAND: bundle
+** COMMAND: bundle|
 **
 ** Usage: %fossil bundle SUBCOMMAND ARGS...
 **
 **   fossil bundle append BUNDLE FILE...
 **

Index: src/checkin.c
==================================================================
--- src/checkin.c
+++ src/checkin.c
@@ -350,12 +350,12 @@
   if( relPathOption ){ relativePaths = 1; }
   return relativePaths;
 }
 
 /*
-** COMMAND: changes
-** COMMAND: status
+** COMMAND: changes|
+** COMMAND: status|
 **
 ** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
 **
 ** Report the change status of files in the current checkout.  If one or
 ** more PATHS are specified, only changes among the named files and
@@ -644,11 +644,11 @@
   }
   db_finalize(&q);
 }
 
 /*
-** COMMAND: ls
+** COMMAND: ls|
 **
 ** Usage: %fossil ls ?OPTIONS? ?PATHS ...?
 **
 ** List all files in the current checkout.  If PATHS is included, only the
 ** named files (or their children if directories) are shown.
@@ -802,11 +802,11 @@
   }
   db_finalize(&q);
 }
 
 /*
-** COMMAND: extras
+** COMMAND: extras|
 **
 ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
 **
 ** Print a list of all files in the source tree that are not part of the
 ** current checkout. See also the "clean" command. If paths are specified,
@@ -872,11 +872,11 @@
   }
   blob_reset(&report);
 }
 
 /*
-** COMMAND: clean
+** COMMAND: clean|
 **
 ** Usage: %fossil clean ?OPTIONS? ?PATH ...?
 **
 ** Delete all "extra" files in the source tree.  "Extra" files are files
 ** that are not officially part of the checkout.  If one or more PATH

Index: src/clone.c
==================================================================
--- src/clone.c
+++ src/clone.c
@@ -209,14 +209,14 @@
     db_open_repository(g.argv[3]);
   }
   db_begin_transaction();
   fossil_print("Rebuilding repository meta-data...\n");
   rebuild_db(0, 1, 0);
-  fossil_print("Extra delta compression... "); fflush(stdout);
+  fossil_print("Extra delta compression... "); fflush(our_stdout);
   extra_deltification();
   db_end_transaction(0);
-  fossil_print("\nVacuuming the database... "); fflush(stdout);
+  fossil_print("\nVacuuming the database... "); fflush(our_stdout);
   if( db_int(0, "PRAGMA page_count")>1000
    && db_int(0, "PRAGMA page_size")<8192 ){
      db_multi_exec("PRAGMA page_size=8192;");
   }
   db_multi_exec("VACUUM");

Index: src/content.c
==================================================================
--- src/content.c
+++ src/content.c
@@ -308,11 +308,11 @@
   }
   return rc;
 }
 
 /*
-** COMMAND: artifact*
+** COMMAND: artifact*|
 **
 ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
 **
 ** Extract an artifact by its artifact hash and write the results on
 ** standard output, or if the optional 4th argument is given, in
@@ -921,11 +921,11 @@
     const char *zUuid = db_column_text(&q, 1);
     int nUuid = db_column_bytes(&q, 1);
     int size = db_column_int(&q, 2);
     n1++;
     fossil_print("  %d/%d\r", n1, total);
-    fflush(stdout);
+    fflush(our_stdout);
     if( size<0 ){
       fossil_print("skip phantom %d %s\n", rid, zUuid);
       continue;  /* Ignore phantoms */
     }
     content_get(rid, &content);

Index: src/db.c
==================================================================
--- src/db.c
+++ src/db.c
@@ -2775,10 +2775,11 @@
   { "max-upload",       0,             25, 0, 0, "250000"              },
   { "mtime-changes",    0,              0, 0, 0, "on"                  },
 #if FOSSIL_ENABLE_LEGACY_MV_RM
   { "mv-rm-files",      0,              0, 0, 0, "off"                 },
 #endif
+  { "pager-command",    0,             40, 0, 0, ""                    },
   { "pgp-command",      0,             40, 0, 0, "gpg --clearsign -o " },
   { "proxy",            0,             32, 0, 0, "off"                 },
   { "relative-paths",   0,              0, 0, 0, "on"                  },
   { "repo-cksum",       0,              0, 0, 0, "on"                  },
   { "self-register",    0,              0, 0, 0, "off"                 },
@@ -3000,10 +3001,15 @@
 **                     support), the "mv" and "rename" commands will also move
 **                     the associated files within the checkout -AND- the "rm"
 **                     and "delete" commands will also remove the associated
 **                     files from within the checkout.  Default: off.
 **
+**
+**    pager-command    Pager command to run when some commands outputs don't
+**                     fit on a single screen. PAGER environment variable has
+**                     precedence over this setting.
+**
 **    pgp-command      Command used to clear-sign manifests at check-in.
 **                     The default is "gpg --clearsign -o ".
 **
 **    proxy            URL of the HTTP proxy.  If undefined or "off" then
 **                     the "http_proxy" environment variable is consulted.

Index: src/descendants.c
==================================================================
--- src/descendants.c
+++ src/descendants.c
@@ -265,11 +265,11 @@
     rid, N
   );
 }
 
 /*
-** COMMAND: descendants*
+** COMMAND: descendants*|
 **
 ** Usage: %fossil descendants ?CHECKIN? ?OPTIONS?
 **
 ** Find all leaf descendants of the check-in specified or if the argument
 ** is omitted, of the check-in currently checked out.
@@ -317,11 +317,11 @@
   print_timeline(&q, 0, width, 0);
   db_finalize(&q);
 }
 
 /*
-** COMMAND: leaves*
+** COMMAND: leaves*|
 **
 ** Usage: %fossil leaves ?OPTIONS?
 **
 ** Find leaves of all branches.  By default show only open leaves.
 ** The -a|--all flag causes all leaves (closed and open) to be shown.

Index: src/diff.c
==================================================================
--- src/diff.c
+++ src/diff.c
@@ -2459,13 +2459,13 @@
   @ </pre>
   style_footer();
 }
 
 /*
-** COMMAND: annotate
-** COMMAND: blame
-** COMMAND: praise
+** COMMAND: annotate|
+** COMMAND: blame|
+** COMMAND: praise|
 **
 ** Usage: %fossil (annotate|blame|praise) ?OPTIONS? FILENAME
 **
 ** Output the text of a file with markings to show when each line of
 ** the file was last modified.  The "annotate" command shows line numbers

Index: src/diffcmd.c
==================================================================
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -784,11 +784,11 @@
   if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
   return zBinGlob;
 }
 
 /*
-** COMMAND: diff
+** COMMAND: diff|
 ** COMMAND: gdiff
 **
 ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...?
 **
 ** Show the difference between the current version of each of the FILEs

Index: src/dispatch.c
==================================================================
--- src/dispatch.c
+++ src/dispatch.c
@@ -44,15 +44,16 @@
 #define CMDFLAG_1ST_TIER  0x0001      /* Most important commands */
 #define CMDFLAG_2ND_TIER  0x0002      /* Obscure and seldom used commands */
 #define CMDFLAG_TEST      0x0004      /* Commands for testing only */
 #define CMDFLAG_WEBPAGE   0x0008      /* Web pages */
 #define CMDFLAG_COMMAND   0x0010      /* A command */
+#define CMDFLAG_PAGINATE  0x0020      /* A command which can be paginated */
 /**************************************************************************/
 
 /* Values for the 2nd parameter to dispatch_name_search() */
 #define CMDFLAG_ANY       0x0018      /* Match anything */
-#define CMDFLAG_PREFIX    0x0020      /* Prefix match is ok */
+#define CMDFLAG_PREFIX    0x0040      /* Prefix match is ok */
 
 #endif /* INTERFACE */
 
 /*
 ** The page_index.h file contains the definition for aCommand[] - an array

Index: src/finfo.c
==================================================================
--- src/finfo.c
+++ src/finfo.c
@@ -19,11 +19,11 @@
 */
 #include "config.h"
 #include "finfo.h"
 
 /*
-** COMMAND: finfo
+** COMMAND: finfo|
 **
 ** Usage: %fossil finfo ?OPTIONS? FILENAME
 **
 ** Print the complete change history for a single file going backwards
 ** in time.  The default mode is -l.
@@ -234,11 +234,11 @@
     blob_reset(&fname);
   }
 }
 
 /*
-** COMMAND: cat
+** COMMAND: cat|
 **
 ** Usage: %fossil cat FILENAME ... ?OPTIONS?
 **
 ** Print on standard output the content of one or more files as they exist
 ** in the repository.  The version currently checked out is shown by default.

Index: src/http_transport.c
==================================================================
--- src/http_transport.c
+++ src/http_transport.c
@@ -315,11 +315,11 @@
   }else if( pUrlData->isFile ){
     got = fread(zBuf, 1, N, transport.pFile);
   }else{
     got = socket_receive(0, zBuf, N);
   }
-  /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
+  /* printf("received %d of %d bytes\n", got, N); fflush(our_stdout); */
   if( transport.pLog ){
     fwrite(zBuf, 1, got, transport.pLog);
     fflush(transport.pLog);
   }
   return got;
@@ -334,16 +334,16 @@
   int nByte = 0;    /* Bytes of content received */
 
   onHand = transport.nUsed - transport.iCursor;
   if( g.fSshTrace){
     printf("Reading %d bytes with %d on hand...  ", N, onHand);
-    fflush(stdout);
+    fflush(our_stdout);
   }
   if( onHand>0 ){
     int toMove = onHand;
     if( toMove>N ) toMove = N;
-    /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
+    /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(our_stdout); */
     memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
     transport.iCursor += toMove;
     if( transport.iCursor>=transport.nUsed ){
       transport.nUsed = 0;
       transport.iCursor = 0;
@@ -456,10 +456,10 @@
 ** Close SSH transport.
 */
 void transport_ssh_close(void){
   if( sshPid ){
     /*printf("Closing SSH tunnel: ");*/
-    fflush(stdout);
+    fflush(our_stdout);
     pclose2(sshIn, sshOut, sshPid);
     sshPid = 0;
   }
 }

Index: src/import.c
==================================================================
--- src/import.c
+++ src/import.c
@@ -586,11 +586,11 @@
     }else
     if( strncmp(zLine, "progress ", 9)==0 ){
       gg.xFinish();
       trim_newline(&zLine[9]);
       fossil_print("%s\n", &zLine[9]);
-      fflush(stdout);
+      fflush(our_stdout);
     }else
     if( strncmp(zLine, "data ", 5)==0 ){
       fossil_free(gg.aData); gg.aData = 0;
       gg.nData = atoi(&zLine[5]);
       if( gg.nData ){
@@ -1872,11 +1872,11 @@
     rebuild_db(0, 1, !incrFlag);
     verify_cancel();
     db_end_transaction(0);
   }
   if( !omitVacuum ){
-    fossil_print("Vacuuming..."); fflush(stdout);
+    fossil_print("Vacuuming..."); fflush(our_stdout);
     db_multi_exec("VACUUM");
   }
   fossil_print(" ok\n");
   if( !incrFlag ){
     fossil_print("project-id: %s\n", db_get("project-code", 0));

Index: src/json.c
==================================================================
--- src/json.c
+++ src/json.c
@@ -604,15 +604,15 @@
     if( g.json.jsonp ){
       cgi_append_content(")",1);
     }
   }else{/*CLI mode*/
     if( g.json.jsonp ){
-      fprintf(stdout,"%s(",g.json.jsonp);
+      fprintf(our_stdout,"%s(",g.json.jsonp);
     }
-    cson_output_FILE( pResponse, stdout, &g.json.outOpt );
+    cson_output_FILE( pResponse, our_stdout, &g.json.outOpt );
     if( g.json.jsonp ){
-      fwrite(")\n", 2, 1, stdout);
+      fwrite(")\n", 2, 1, our_stdout);
     }
   }
 }
 
 /*

Index: src/json_user.c
==================================================================
--- src/json_user.c
+++ src/json_user.c
@@ -350,11 +350,11 @@
 #else /* need name for login group support :/ */
   blob_append_sql(&sql, " WHERE login=%Q", zName);
 #endif
 #if 0
   puts(blob_str(&sql));
-  cson_output_FILE( cson_object_value(pUser), stdout, NULL );
+  cson_output_FILE( cson_object_value(pUser), our_stdout, NULL );
 #endif
   db_prepare(&q, "%s", blob_sql_text(&sql));
   db_exec(&q);
   db_finalize(&q);
 #if TRY_LOGIN_GROUP

Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -22,10 +22,11 @@
 #include "config.h"
 #if defined(_WIN32)
 #  include <windows.h>
 #endif
 #include "main.h"
+#include "popen.h"
 #include <string.h>
 #include <time.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -298,10 +299,13 @@
 
 #endif
 
 Global g;
 
+static int pagerPid = 0;             /* Process id of pager subprocess */
+extern FILE *our_stdout;
+
 /*
 ** atexit() handler which frees up "some" of the resources
 ** used by fossil.
 */
 static void fossil_atexit(void) {
@@ -347,10 +351,15 @@
     if( g.interp ){
       Th_DeleteInterp(g.interp); g.interp = 0;
     }
     assert( Th_GetOutstandingMalloc()==0 );
   }
+
+  if( pagerPid>0 ){
+    /* Close connection with pager process */
+    pclose2(0, our_stdout, pagerPid);
+  }
 }
 
 /*
 ** Convert all arguments from mbcs (or unicode) to UTF-8. Then
 ** search g.argv for arguments "--args FILENAME". If found, then
@@ -553,10 +562,12 @@
 #endif
 {
   const char *zCmdName = "unknown";
   const CmdOrPage *pCmd = 0;
   int rc;
+  char *pager;
+  our_stdout = stdout;
   if( sqlite3_libversion_number()<3014000 ){
     fossil_fatal("Unsuitable SQLite version %s, must be at least 3.14.0",
                  sqlite3_libversion());
   }
   sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -755,10 +766,25 @@
     rc = TH_OK;
   }
   if( rc==TH_OK || rc==TH_RETURN || rc==TH_CONTINUE ){
     if( rc==TH_OK || rc==TH_RETURN ){
 #endif
+
+      if( !g.isHTTP && (pCmd->eCmdFlags & CMDFLAG_PAGINATE) && is_tty(stdout) ){
+        pager = fossil_getenv("PAGER");
+        if( pager==0 ){
+          db_find_and_open_repository(0, 0);
+          pager = db_get("pager-command", 0);
+        }
+        if( pager != 0 && strcmp(pager, "")!=0 ){
+          /* Launch pager as a subprocess and pipe our output to its input */
+          if( popen2(pager, 0, &our_stdout, &pagerPid) != 0 ){
+            our_stdout = stdout;
+          }
+        }
+      }
+
       pCmd->xFunc();
 #ifdef FOSSIL_ENABLE_TH1_HOOKS
     }
     if( !g.isHTTP && !g.fNoThHook && (rc==TH_OK || rc==TH_CONTINUE) ){
       Th_CommandNotify(pCmd->zName, pCmd->eCmdFlags);

Index: src/merge3.c
==================================================================
--- src/merge3.c
+++ src/merge3.c
@@ -492,11 +492,11 @@
         azSubst[0] = "%baseline";  azSubst[1] = zPivot;
         azSubst[2] = "%original";  azSubst[3] = zOrig;
         azSubst[4] = "%merge";     azSubst[5] = zOther;
         azSubst[6] = "%output";    azSubst[7] = zOut;
         zCmd = string_subst(zGMerge, 8, azSubst);
-        printf("%s\n", zCmd); fflush(stdout);
+        printf("%s\n", zCmd); fflush(our_stdout);
         fossil_system(zCmd);
         if( file_wd_size(zOut)>=0 ){
           blob_read_from_file(pOut, zOut);
           file_delete(zPivot);
           file_delete(zOrig);

Index: src/mkindex.c
==================================================================
--- src/mkindex.c
+++ src/mkindex.c
@@ -42,15 +42,21 @@
 **
 ** Commands are 1st-tier by default.  If the command name begins with
 ** "test-" or if the command name has a "test" argument, then it becomes
 ** a test command.  If the command name has a "2nd-tier" argument or ends
 ** with a "*" character, it is second tier.  Examples:
+** If the command name has a "paginate" argument or ends with
+** a "|" character, its output can be sent through a pager.  Examples:
 **
 **        COMMAND:  abcde*
 **        COMMAND:  fghij        2nd-tier
 **        COMMAND:  test-xyzzy
 **        COMMAND:  xyzzy        test
+**        COMMAND:  paginated1|
+**        COMMAND:  paginated2   paginate
+**        COMMAND:  paginatedand2ndtier1*|
+**        COMMAND:  paginatedand2ndtier2    2nd-tier paginate
 **
 ** New arguments may be added in future releases that set additional
 ** bits in the eCmdFlags field.
 **
 ** Additional lines of comment after the COMMAND: or WEBPAGE: become
@@ -73,10 +79,11 @@
 #define CMDFLAG_1ST_TIER  0x0001      /* Most important commands */
 #define CMDFLAG_2ND_TIER  0x0002      /* Obscure and seldom used commands */
 #define CMDFLAG_TEST      0x0004      /* Commands for testing only */
 #define CMDFLAG_WEBPAGE   0x0008      /* Web pages */
 #define CMDFLAG_COMMAND   0x0010      /* A command */
+#define CMDFLAG_PAGINATE  0x0020      /* A command which can be paginated */
 /**************************************************************************/
 
 /*
 ** Each entry looks like this:
 */
@@ -191,18 +198,30 @@
   aEntry[nUsed].zFunc = 0;
   if( (eType & CMDFLAG_COMMAND)!=0 ){
     if( strncmp(&zLine[i], "test-", 5)==0 ){
       /* Commands that start with "test-" are test-commands */
       aEntry[nUsed].eType |= CMDFLAG_TEST;
-    }else if( zLine[i+j-1]=='*' ){
-      /* If the command name ends in '*', remove the '*' from the name
-      ** but move the command into the second tier */
-      aEntry[nUsed].zPath[j-1] = 0;
-      aEntry[nUsed].eType |= CMDFLAG_2ND_TIER;
     }else{
-      /* Otherwise, this is a first-tier command */
       aEntry[nUsed].eType |= CMDFLAG_1ST_TIER;
+      while( zLine[i+j-1]=='*' || zLine[i+j-1]=='|' ){
+        if( zLine[i+j-1]=='*' ){
+          /* If the command name ends in '*',
+          ** move the command into the second tier */
+          aEntry[nUsed].eType &= ~CMDFLAG_1ST_TIER;
+          aEntry[nUsed].eType |= CMDFLAG_2ND_TIER;
+        }else if( zLine[i+j-1]=='|' ){
+          /* If the command name ends in '|',
+          ** consider its output can be sent to a pager */
+          aEntry[nUsed].eType |= CMDFLAG_PAGINATE;
+        }
+        aEntry[nUsed].zPath[j-1] = 0;
+        /* replace just processed '*' or '|' by a blank character so that
+         * it is no more part of the command name
+         */
+        zLine[i+j-1] = ' ';
+        j--;
+      }
     }
   }
 
   /* Process additional flags that might follow the command name */
   while( zLine[i+j]!=0 ){
@@ -217,10 +236,12 @@
       aEntry[nUsed].eType &= ~(CMDFLAG_1ST_TIER|CMDFLAG_TEST);
       aEntry[nUsed].eType |= CMDFLAG_2ND_TIER;
     }else if( j==4 && strncmp(&zLine[i], "test", j)==0 ){
       aEntry[nUsed].eType &= ~(CMDFLAG_1ST_TIER|CMDFLAG_2ND_TIER);
       aEntry[nUsed].eType |= CMDFLAG_TEST;
+    }else if( j==8 && strncmp(&zLine[i], "paginate", j)==0 ){
+      aEntry[nUsed].eType |= CMDFLAG_PAGINATE;
     }else{
       fprintf(stderr, "%s:%d: unknown option: '%.*s'\n",
               zFile, nLine, j, &zLine[i]);
       nErr++;
     }

Index: src/popen.c
==================================================================
--- src/popen.c
+++ src/popen.c
@@ -21,15 +21,16 @@
 #include "popen.h"
 
 #ifdef _WIN32
 #include <windows.h>
 #include <fcntl.h>
+#include <string.h>
 /*
 ** Print a fatal error and quit.
 */
 static void win32_fatal_error(const char *zMsg){
-  fossil_fatal("%s", zMsg);
+  fossil_fatal("%s : %d", zMsg, GetLastError());
 }
 #else
 #include <signal.h>
 #include <sys/wait.h>
 #endif
@@ -116,11 +117,13 @@
 ** Create a child process running shell command "zCmd".  *ppOut is
 ** a FILE that becomes the standard input of the child process.
 ** (The caller writes to *ppOut in order to send text to the child.)
 ** *ppIn is stdout from the child process.  (The caller
 ** reads from *ppIn in order to receive input from the child.)
-** Note that *ppIn is an unbuffered file descriptor, not a FILE.
+** Notes concerning *ppIn:
+** 1)It can be NULL if output of child process needs not be captured.
+** 2)It is an unbuffered file descriptor, not a FILE.
 ** The process ID of the child is written into *pChildPid.
 **
 ** Return the number of errors.
 */
 int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
@@ -145,19 +148,23 @@
   SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
 
   win32_create_child_process(fossil_utf8_to_unicode(zCmd),
                              hStdinRd, hStdoutWr, hStderr,&childPid);
   *pChildPid = childPid;
-  *pfdIn = _open_osfhandle(PTR_TO_INT(hStdoutRd), 0);
+  if( pfdIn ){
+    *pfdIn = _open_osfhandle(PTR_TO_INT(hStdoutRd), 0);
+  }
   fd = _open_osfhandle(PTR_TO_INT(hStdinWr), 0);
   *ppOut = _fdopen(fd, "w");
   CloseHandle(hStdinRd);
   CloseHandle(hStdoutWr);
   return 0;
 #else
   int pin[2], pout[2];
-  *pfdIn = 0;
+  if( pfdIn ){
+    *pfdIn = 0;
+  }
   *ppOut = 0;
   *pChildPid = 0;
 
   if( pipe(pin)<0 ){
     return 1;
@@ -184,21 +191,25 @@
     close(0);
     fd = dup(pout[0]);
     if( fd!=0 ) nErr++;
     close(pout[0]);
     close(pout[1]);
-    close(1);
-    fd = dup(pin[1]);
-    if( fd!=1 ) nErr++;
-    close(pin[0]);
-    close(pin[1]);
+    if( pfdIn ){
+      close(1);
+      fd = dup(pin[1]);
+      if( fd!=1 ) nErr++;
+      close(pin[0]);
+      close(pin[1]);
+    }
     execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0);
     return 1;
   }else{
     /* This is the parent process */
     close(pin[1]);
-    *pfdIn = pin[0];
+    if( pfdIn ){
+      *pfdIn = pin[0];
+    }
     close(pout[0]);
     *ppOut = fdopen(pout[1], "w");
     return 0;
   }
 #endif
@@ -205,17 +216,20 @@
 }
 
 /*
 ** Close the connection to a child process previously created using
 ** popen2().
+** fdIn must be >0. Otherwise there won't be any attempt to close it.
 */
 void pclose2(int fdIn, FILE *pOut, int childPid){
 #ifdef _WIN32
   /* Not implemented, yet */
   close(fdIn);
   fclose(pOut);
 #else
-  close(fdIn);
+  if( fdIn>0 ){
+    close(fdIn);
+  }
   fclose(pOut);
-  while( waitpid(0, 0, WNOHANG)>0 ) {}
+  while( waitpid(0, 0, 0)>0 ) {}
 #endif
 }

Index: src/printf.c
==================================================================
--- src/printf.c
+++ src/printf.c
@@ -870,10 +870,17 @@
 ** a line.
 ** was a \n
 */
 static int stdoutAtBOL = 1;
 
+/* The stream used as standard output one
+** Set to:
+** 1)Conventional stdout if no pager is used.
+** 2)Input stream of the pager otherwise.
+*/
+FILE *our_stdout = 0;
+
 /*
 ** Write to standard output or standard error.
 **
 ** On windows, transform the output into the current terminal encoding
 ** if the output is going to the screen.  If output is redirected into
@@ -881,11 +888,11 @@
 ** properly process line-endings, make sure to switch the mode back to
 ** text when done.
 ** No translation ever occurs on unix.
 */
 void fossil_puts(const char *z, int toStdErr){
-  FILE* out = (toStdErr ? stderr : stdout);
+  FILE* out = (toStdErr ? stderr : our_stdout);
   int n = (int)strlen(z);
   if( n==0 ) return;
   assert( toStdErr==0 || toStdErr==1 );
   if( toStdErr==0 ) stdoutAtBOL = (z[n-1]=='\n');
 #if defined(_WIN32)

Index: src/rebuild.c
==================================================================
--- src/rebuild.c
+++ src/rebuild.c
@@ -186,11 +186,11 @@
 */
 static void percent_complete(int permill){
   static int lastOutput = -1;
   if( permill>lastOutput ){
     fossil_print("  %d.%d%% complete...\r", permill/10, permill%10);
-    fflush(stdout);
+    fflush(our_stdout);
     lastOutput = permill;
   }
 }
 
 
@@ -638,11 +638,11 @@
       errCnt
     );
     db_end_transaction(1);
   }else{
     if( runCompress ){
-      fossil_print("Extra delta compression... "); fflush(stdout);
+      fossil_print("Extra delta compression... "); fflush(our_stdout);
       extra_deltification();
       runVacuum = 1;
     }
     if( omitVerify ) verify_cancel();
     db_end_transaction(0);
@@ -657,16 +657,16 @@
       db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
                     "DROP TABLE IF EXISTS sqlite_stat3;"
                     "DROP TABLE IF EXISTS sqlite_stat4;");
     }
     if( runAnalyze ){
-      fossil_print("Analyzing the database... "); fflush(stdout);
+      fossil_print("Analyzing the database... "); fflush(our_stdout);
       db_multi_exec("ANALYZE;");
       fossil_print("done\n");
     }
     if( runVacuum ){
-      fossil_print("Vacuuming the database... "); fflush(stdout);
+      fossil_print("Vacuuming the database... "); fflush(our_stdout);
       db_multi_exec("VACUUM");
       fossil_print("done\n");
     }
     if( activateWal ){
       db_multi_exec("PRAGMA journal_mode=WAL;");
@@ -934,11 +934,11 @@
         }
         content_put(&aContent);
         blob_reset(&path);
         blob_reset(&aContent);
         fossil_print("\r%d", ++nFileRead);
-        fflush(stdout);
+        fflush(our_stdout);
       }
       free(zSubpath);
     }
     closedir(d);
   }else {
@@ -1068,11 +1068,11 @@
   bag_init(&bagDone);
   ttyOutput = 1;
   processCnt = 0;
   if (!g.fQuiet) {
     fossil_print("0 (0%%)...\r");
-    fflush(stdout);
+    fflush(our_stdout);
   }
   totalSize = db_int(0, "SELECT count(*) FROM blob");
   db_prepare(&s,
      "SELECT rid, size FROM blob /*scan*/"
      " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"

Index: src/search.c
==================================================================
--- src/search.c
+++ src/search.c
@@ -552,11 +552,11 @@
 }
 
 /*
 ** Testing the search function.
 **
-** COMMAND: search*
+** COMMAND: search*|
 **
 ** Usage: %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern...
 **
 ** Search for timeline entries matching all words provided on the
 ** command line. Whole-word matches scope more highly than partial
@@ -1674,11 +1674,11 @@
 /*
 ** Construct, prepopulate, and then update the full-text index.
 */
 void search_rebuild_index(void){
   fossil_print("rebuilding the search index...");
-  fflush(stdout);
+  fflush(our_stdout);
   search_create_index();
   search_fill_index();
   search_update_index(search_restrict(SRCH_ALL));
   fossil_print(" done\n");
 }

Index: src/tag.c
==================================================================
--- src/tag.c
+++ src/tag.c
@@ -363,11 +363,11 @@
   assert( blob_is_reset(&ctrl) );
   manifest_to_disk(rid);
 }
 
 /*
-** COMMAND: tag
+** COMMAND: tag|
 **
 ** Usage: %fossil tag SUBCOMMAND ...
 **
 ** Run various subcommands to control tags and properties.
 **

Index: src/timeline.c
==================================================================
--- src/timeline.c
+++ src/timeline.c
@@ -2310,11 +2310,11 @@
 static int fossil_is_julianday(const char *zDate){
   return db_int(0, "SELECT EXISTS (SELECT julianday(%Q) AS jd WHERE jd IS NOT NULL)", zDate);
 }
 
 /*
-** COMMAND: timeline
+** COMMAND: timeline|
 **
 ** Usage: %fossil timeline ?WHEN? ?CHECKIN|DATETIME? ?OPTIONS?
 **
 ** Print a summary of activity going backwards in date and time
 ** specified or from the current date and time if no arguments

Index: src/tkt.c
==================================================================
--- src/tkt.c
+++ src/tkt.c
@@ -1048,11 +1048,11 @@
   }
   @ </ol>
 }
 
 /*
-** COMMAND: ticket*
+** COMMAND: ticket*|
 **
 ** Usage: %fossil ticket SUBCOMMAND ...
 **
 ** Run various subcommands to control tickets
 **

Index: src/undo.c
==================================================================
--- src/undo.c
+++ src/undo.c
@@ -425,12 +425,12 @@
   fossil_print("Rolling back prior filesystem changes...\n");
   undo_all_filesystem(0);
 }
 
 /*
-** COMMAND: undo
-** COMMAND: redo*
+** COMMAND: undo|
+** COMMAND: redo*|
 **
 ** Usage: %fossil undo ?OPTIONS? ?FILENAME...?
 **    or: %fossil redo ?OPTIONS? ?FILENAME...?
 **
 ** Undo the changes to the working checkout caused by the most recent

Index: src/unversioned.c
==================================================================
--- src/unversioned.c
+++ src/unversioned.c
@@ -201,12 +201,12 @@
   }
   return 0;
 }
 
 /*
-** COMMAND: uv*
-** COMMAND: unversioned
+** COMMAND: uv*|
+** COMMAND: unversioned|
 **
 ** Usage: %fossil unversioned SUBCOMMAND ARGS...
 **    or: %fossil uv SUBCOMMAND ARGS..
 **
 ** Unversioned files (UV-files) are artifacts that are synced and are available

Index: src/util.c
==================================================================
--- src/util.c
+++ src/util.c
@@ -23,18 +23,20 @@
 /*
 ** For the fossil_timer_xxx() family of functions...
 */
 #ifdef _WIN32
 # include <windows.h>
+# include <io.h>
 #else
 # include <sys/time.h>
 # include <sys/resource.h>
 # include <unistd.h>
 # include <fcntl.h>
 # include <errno.h>
 #endif
 
+# include <stdio.h>
 
 /*
 ** Exit.  Take care to close the database first.
 */
 NORETURN void fossil_exit(int rc){
@@ -378,10 +380,21 @@
   return 1;
 #else
   return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
 #endif
 }
+
+/*
+** Return TRUE if stream is a terminal.
+*/
+int is_tty(FILE *stream){
+#ifdef _WIN32
+  return (stream!=0) && _isatty(_fileno(stream));
+#else
+  return (stream!=0) && isatty(fileno(stream));
+#endif
+}
 
 /*
 ** Returns TRUE if zSym is exactly UUID_SIZE bytes long and contains
 ** only lower-case ASCII hexadecimal values.
 */

Index: src/wiki.c
==================================================================
--- src/wiki.c
+++ src/wiki.c
@@ -1154,11 +1154,11 @@
   }
   return rid;
 }
 
 /*
-** COMMAND: wiki*
+** COMMAND: wiki*|
 **
 ** Usage: %fossil wiki (export|create|commit|list) WikiName
 **
 ** Run various subcommands to work with wiki entries or tech notes.
 **

_______________________________________________
fossil-users mailing list
fossil-users@lists.fossil-scm.org
http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users

Reply via email to