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