/* ** Copyright (c) 2016 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to map command names (ex: "help", "commit", ** "diff") or webpage names (ex: "/timeline", "/search") into the functions ** that implement those commands and web pages and their associated help ** text. */ #include "config.h" #include #include "dispatch.h" #if INTERFACE /* ** An instance of this object defines everything we need to know about an ** individual command or webpage. */ struct CmdOrPage { const char *zName; /* Name. Webpages start with "/". Commands do not */ void (*xFunc)(void); /* Function that implements the command or webpage */ const char *zHelp; /* Raw help text */ unsigned int eCmdFlags; /* Flags */ }; /*************************************************************************** ** These macros must match similar macros in mkindex.c ** Allowed values for CmdOrPage.eCmdFlags. */ #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 */ /**************************************************************************/ /* Values for the 2nd parameter to dispatch_name_search() */ #define CMDFLAG_ANY 0x0018 /* Match anything */ #define CMDFLAG_PREFIX 0x0020 /* Prefix match is ok */ #endif /* INTERFACE */ /* ** The page_index.h file contains the definition for aCommand[] - an array ** of CmdOrPage objects that defines all available commands and webpages ** known to Fossil. ** ** The entries in aCommand[] are in sorted order by name. Since webpage names ** always begin with "/", all webpage names occur first. The page_index.h file ** also sets the FOSSIL_FIRST_CMD macro to be the *approximate* index ** in aCommand[] of the first command entry. FOSSIL_FIRST_CMD might be ** slightly too low, and so the range FOSSIL_FIRST_CMD...MX_COMMAND might ** contain a few webpage entries at the beginning. ** ** The page_index.h file is generated by the mkindex program which scans all ** source code files looking for header comments on the functions that ** implement command and webpages. */ #include "page_index.h" #define MX_COMMAND (sizeof(aCommand)/sizeof(aCommand[0])) /* ** Given a command or webpage name in zName, find the corresponding CmdOrPage ** object and return a pointer to that object in *ppCmd. ** ** The eType field is CMDFLAG_COMMAND to lookup commands or CMDFLAG_WEBPAGE ** to look up webpages or CMDFLAG_ANY to look for either. If the CMDFLAG_PREFIX ** flag is set, then a prefix match is allowed. ** ** Return values: ** 0: Success. *ppCmd is set to the appropriate CmdOrPage ** 1: Not found. ** 2: Ambiguous. Two or more entries match. */ int dispatch_name_search( const char *zName, /* Look for this name */ unsigned eType, /* CMDFLAGS_* bits */ const CmdOrPage **ppCmd /* Write the matching CmdOrPage object here */ ){ int upr, lwr, mid; int nName = strlen(zName); lwr = 0; upr = MX_COMMAND - 1; while( lwr<=upr ){ int c; mid = (upr+lwr)/2; c = strcmp(zName, aCommand[mid].zName); if( c==0 ){ *ppCmd = &aCommand[mid]; return 0; /* An exact match */ }else if( c<0 ){ upr = mid - 1; }else{ lwr = mid + 1; } } if( (eType & CMDFLAG_PREFIX)!=0 && lwr\n%h\n\n", z); fossil_free(z); } /* ** COMMAND: test-all-help ** ** Usage: %fossil test-all-help ?OPTIONS? ** ** Show help text for commands and pages. Useful for proof-reading. ** Defaults to just the CLI commands. Specify --www to see only the ** web pages, or --everything to see both commands and pages. ** ** Options: ** -e|--everything Show all commands and pages. ** -t|--test Include test- commands ** -w|--www Show WWW pages. ** -h|--html Transform output to HTML. */ void test_all_help_cmd(void){ int i; int mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER; int useHtml = find_option("html","h",0)!=0; if( find_option("www","w",0) ){ mask = CMDFLAG_WEBPAGE; } if( find_option("everything","e",0) ){ mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER | CMDFLAG_WEBPAGE; } if( find_option("test","t",0) ){ mask |= CMDFLAG_TEST; } if( useHtml ) fossil_print("\n"); fossil_print("\n"); }else{ fossil_print("---\n"); } for(i=0; i\n"); }else{ fossil_print("---\n"); } version_cmd(); } /* ** WEBPAGE: help ** URL: /help?name=CMD ** ** Show the built-in help text for CMD. CMD can be a command-line interface ** command or a page name from the web interface. */ void help_page(void){ const char *zCmd = P("cmd"); if( zCmd==0 ) zCmd = P("name"); style_header("Command-line Help"); if( zCmd ){ int rc; const CmdOrPage *pCmd = 0; style_submenu_element("Command-List", "Command-List", "%s/help", g.zTop); if( *zCmd=='/' ){ /* Some of the webpages require query parameters in order to work. ** @

The "%s(zCmd)" page:

*/ @

The "%s(zCmd)" page:

}else{ @

The "%s(zCmd)" command:

} rc = dispatch_name_search(zCmd, CMDFLAG_ANY, &pCmd); if( rc==1 ){ @ unknown command: %s(zCmd) }else if( rc==2 ){ @ ambiguous command prefix: %s(zCmd) }else{ if( pCmd->zHelp[0]==0 ){ @ no help available for the %s(pCmd->zName) command }else{ @
help_to_html(pCmd->zHelp, cgi_output_blob()); @
} } }else{ int i, j, n; @

Available commands:

@ for(i=j=0; i
    } @
  • %s(z)
  • j++; if( j>=n ){ @
j = 0; } } if( j>0 ){ @ } @
@

Available web UI pages:

@ for(i=j=0; i
    } if( aCommand[i].zHelp[0] ){ @
  • %s(z+1)
  • }else{ @
  • %s(z+1)
  • } j++; if( j>=n ){ @
j = 0; } } if( j>0 ){ @ } @
@

Unsupported commands:

@ for(i=j=0; i
    } if( aCommand[i].zHelp[0] ){ @
  • %s(z)
  • }else{ @
  • %s(z)
  • } j++; if( j>=n ){ @
j = 0; } } if( j>0 ){ @ } @
} style_footer(); } /* ** WEBPAGE: test-all-help ** ** Show all help text on a single page. Useful for proof-reading. */ void test_all_help_page(void){ int i; style_header("Testpage: All Help Text"); for(i=0; i%s(aCommand[i].zName): @
help_to_html(aCommand[i].zHelp, cgi_output_blob()); @
} style_footer(); } static void multi_column_list(const char **azWord, int nWord){ int i, j, len; int mxLen = 0; int nCol; int nRow; for(i=0; imxLen ) mxLen = len; } nCol = 80/(mxLen+2); if( nCol==0 ) nCol = 1; nRow = (nWord + nCol - 1)/nCol; for(i=0; izHelp; if( z==0 ){ fossil_fatal("no help available for the %s %s", pCmd->zName, zCmdOrPage); } while( *z ){ if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ fossil_print("%s", g.argv[0]); z += 7; }else{ putchar(*z); z++; } } putchar('\n'); }