Hi all,

First of all many thanks for all your feedback.

I come back to you with an implemented solution.

After many thinking, for me not all commands need to send their outputs to
a pager.
Only ones which may output a big amount of lines in a bunch.
Therefore, I selected only some of them to be candidate for a pager:

   1. branch
   2. bundle
   3. changes
   4. status
   5. ls
   6. extras
   7. clean
   8. artifact
   9. descendants
   10. leaves
   11. annotate
   12. blame
   13. praise
   14. diff
   15. finfo
   16. cat
   17. json
   18. search
   19. tag
   20. timeline
   21. ticket
   22. undo
   23. redo
   24. unversioned
   25. wiki

To achieve that, I modified mkindex.c and, in all relevant source files, I
appended a pipe '|' to the commands which are candidates for a pager.


Now, when fossil is launched, it decides whether to use a pager according
to following conditions in this order of priority:

   1. Fossil command is candidate for a pager.
   2. PAGER environment variable is set to a non empty value.
   3. pager-command setting is set to a non empty value.


Then, technically, when there is pager to use it is launched as a child
process and Fossil standard output stream is piped to pager standard input.

And Fossil waits for pager to quit before quitting itself.


Just give it a try : it works pretty well under Linux with pager-command
"less -FRX".

It does not work yet under Windows as I'm a complete newbie with its
programming API.

If someone wants to contribute for the Windows, it would be welcome.


As usual, waiting for your feedback ...

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);
     }
   }
 }
 
 /*
@@ -2242,11 +2242,11 @@
 /* dupe ifdef needed for mkindex */
 /*
 ** This function dispatches json commands and is the CLI equivalent of
 ** json_page_top().
 **
-** COMMAND: json
+** COMMAND: json|
 **
 ** Usage: %fossil json SUBCOMMAND ?OPTIONS?
 **
 ** In CLI mode, the -R REPO common option is supported. Due to limitations
 ** in the argument dispatching code, any -FLAGS must come after the final

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) ){
+        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/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
[email protected]
http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users

Reply via email to