Fossil

Check-in [246ac307]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge trunk into ben-testing, adjusting for versionable settings.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ben-testing
Files: files | file ages | folders
SHA1:246ac307bb0438c23cfc66fc9cb15412992219a4
User & Date: ben 2011-08-14 07:21:58
Context
2011-08-14
17:54
Remove the seperate versionable version of db_get(), which now uses ctrlSettings to determine whether a setting is versionable or not. check-in: 3113f7b1 user: ben tags: ben-testing
07:21
Merge trunk into ben-testing, adjusting for versionable settings. check-in: 246ac307 user: ben tags: ben-testing
07:13
Change the relative-paths default to 'on', after feedback from the community. check-in: 42a830e7 user: ben tags: ben-testing
2011-08-12
12:13
Fix harmless compiler warnings in tar.c. check-in: 073725ae user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/add.c.

    90     90   /*
    91     91   ** Add a single file named zName to the VFILE table with vid.
    92     92   **
    93     93   ** Omit any file whose name is pOmit.
    94     94   */
    95     95   static int add_one_file(
    96     96     const char *zPath,   /* Tree-name of file to add. */
    97         -  int vid              /* Add to this VFILE */
           97  +  int vid,             /* Add to this VFILE */
           98  +  int caseSensitive    /* True if filenames are case sensitive */
    98     99   ){
          100  +  const char *zCollate = caseSensitive ? "binary" : "nocase";
    99    101     if( !file_is_simple_pathname(zPath) ){
   100    102       fossil_fatal("filename contains illegal characters: %s", zPath);
   101    103     }
   102         -#if defined(_WIN32)
   103    104     if( db_exists("SELECT 1 FROM vfile"
   104         -                " WHERE pathname=%Q COLLATE nocase", zPath) ){
          105  +                " WHERE pathname=%Q COLLATE %s", zPath, zCollate) ){
   105    106       db_multi_exec("UPDATE vfile SET deleted=0"
   106         -                  " WHERE pathname=%Q COLLATE nocase", zPath);
   107         -  }
   108         -#else
   109         -  if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){
   110         -    db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath);
   111         -  }
   112         -#endif
   113         -  else{
          107  +                  " WHERE pathname=%Q COLLATE %s", zPath, zCollate);
          108  +  }else{
   114    109       char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
   115    110       db_multi_exec(
   116    111         "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)"
   117    112         "VALUES(%d,0,0,0,%Q,%d)",
   118    113         vid, zPath, file_isexe(zFullname));
   119    114       fossil_free(zFullname);
   120    115     }
   121         -  fossil_print("ADDED  %s\n", zPath);
   122         -  return 1;
          116  +  if( db_changes() ){
          117  +    fossil_print("ADDED  %s\n", zPath);
          118  +    return 1;
          119  +  }else{
          120  +    fossil_print("SKIP   %s\n", zPath);
          121  +    return 0;
          122  +  }
   123    123   }
   124    124   
   125    125   /*
   126    126   ** Add all files in the sfile temp table.
   127    127   **
   128    128   ** Automatically exclude the repository file.
   129    129   */
   130         -static int add_files_in_sfile(int vid){
          130  +static int add_files_in_sfile(int vid, int caseSensitive){
   131    131     const char *zRepo;        /* Name of the repository database file */
   132    132     int nAdd = 0;             /* Number of files added */
   133    133     int i;                    /* Loop counter */
   134    134     const char *zReserved;    /* Name of a reserved file */
   135    135     Blob repoName;            /* Treename of the repository */
   136    136     Stmt loop;                /* SQL to loop over all files to add */
          137  +  int (*xCmp)(const char*,const char*);
   137    138    
   138    139     if( !file_tree_name(g.zRepositoryName, &repoName, 0) ){
   139    140       blob_zero(&repoName);
   140    141       zRepo = "";
   141    142     }else{
   142    143       zRepo = blob_str(&repoName);
          144  +  }
          145  +  if( caseSensitive ){
          146  +    xCmp = fossil_strcmp;
          147  +  }else{
          148  +    xCmp = fossil_stricmp;
          149  +    db_multi_exec(
          150  +      "CREATE INDEX IF NOT EXISTS vfile_nocase"
          151  +      "    ON vfile(pathname COLLATE nocase)"
          152  +    );
   143    153     }
   144    154     db_prepare(&loop, "SELECT x FROM sfile ORDER BY x");
   145    155     while( db_step(&loop)==SQLITE_ROW ){
   146    156       const char *zToAdd = db_column_text(&loop, 0);
   147    157       if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
   148    158       for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){
   149         -      if( fossil_strcmp(zToAdd, zReserved)==0 ) break;
          159  +      if( xCmp(zToAdd, zReserved)==0 ) break;
   150    160       }
   151    161       if( zReserved ) continue;
   152         -    nAdd += add_one_file(zToAdd, vid);
          162  +    nAdd += add_one_file(zToAdd, vid, caseSensitive);
   153    163     }
   154    164     db_finalize(&loop);
   155    165     blob_reset(&repoName);
   156    166     return nAdd;
   157    167   }
   158    168   
   159    169   /*
................................................................................
   178    188   */
   179    189   void add_cmd(void){
   180    190     int i;                     /* Loop counter */
   181    191     int vid;                   /* Currently checked out version */
   182    192     int nRoot;                 /* Full path characters in g.zLocalRoot */
   183    193     const char *zIgnoreFlag;   /* The --ignore option or ignore-glob setting */
   184    194     Glob *pIgnore;             /* Ignore everything matching this glob pattern */
          195  +  int caseSensitive;         /* True if filenames are case sensitive */
   185    196   
   186    197     zIgnoreFlag = find_option("ignore",0,1);
   187    198     includeDotFiles = find_option("dotfiles",0,0)!=0;
          199  +  capture_case_sensitive_option();
   188    200     db_must_be_within_tree();
          201  +  caseSensitive = filenames_are_case_sensitive();
   189    202     if( zIgnoreFlag==0 ){
   190    203       zIgnoreFlag = db_get_versionable_setting("ignore-glob", 0);
   191    204     }
   192    205     vid = db_lget_int("checkout",0);
   193    206     if( vid==0 ){
   194    207       fossil_panic("no checkout to add to");
   195    208     }
................................................................................
   227    240            zTreeName, zTreeName
   228    241         );
   229    242       }
   230    243       blob_reset(&fullName);
   231    244     }
   232    245     glob_free(pIgnore);
   233    246   
   234         -  add_files_in_sfile(vid);  
          247  +  add_files_in_sfile(vid, caseSensitive);
   235    248     db_end_transaction(0);
   236    249   }
   237    250   
   238    251   /*
   239    252   ** COMMAND: rm
   240    253   ** COMMAND: delete
   241    254   **
................................................................................
   287    300     db_finalize(&loop);
   288    301     db_multi_exec(
   289    302       "UPDATE vfile SET deleted=1 WHERE pathname IN sfile;"
   290    303       "DELETE FROM vfile WHERE rid=0 AND deleted;"
   291    304     );
   292    305     db_end_transaction(0);
   293    306   }
          307  +
          308  +/*
          309  +** Capture the command-line --case-sensitive option.
          310  +*/
          311  +static const char *zCaseSensitive = 0;
          312  +void capture_case_sensitive_option(void){
          313  +  if( zCaseSensitive==0 ){
          314  +    zCaseSensitive = find_option("case-sensitive",0,1);
          315  +  }
          316  +}
          317  +
          318  +/*
          319  +** This routine determines if files should be case-sensitive or not.
          320  +** In other words, this routine determines if two filenames that
          321  +** differ only in case should be considered the same name or not.
          322  +**
          323  +** The case-sensitive setting determines the default value.  If
          324  +** the case-sensitive setting is undefined, then case sensitivity
          325  +** defaults on for Mac and Windows and off for all other unix.
          326  +**
          327  +** The --case-sensitive BOOLEAN command-line option overrides any
          328  +** setting.
          329  +*/
          330  +int filenames_are_case_sensitive(void){
          331  +  int caseSensitive;
          332  +
          333  +  if( zCaseSensitive ){
          334  +    caseSensitive = is_truth(zCaseSensitive);
          335  +  }else{
          336  +#if !defined(_WIN32) && !defined(__DARWIN__) && !defined(__APPLE__)
          337  +    caseSensitive = 1;
          338  +#else
          339  +    caseSensitive = 0;
          340  +#endif
          341  +    caseSensitive = db_get_boolean("case-sensitive",caseSensitive);
          342  +  }
          343  +  return caseSensitive;
          344  +}
   294    345   
   295    346   /*
   296    347   ** COMMAND: addremove
   297    348   **
   298    349   ** Usage: %fossil addremove ?--dotfiles? ?--ignore GLOBPATTERN? ?--test?
   299    350   **
   300    351   ** Do all necessary "add" and "rm" commands to synchronize the repository
................................................................................
   317    368   ** The --ignore option overrides the "ignore-glob" setting.  See
   318    369   ** documentation on the "settings" command for further information.
   319    370   **
   320    371   ** The --test option shows what would happen without actually doing anything.
   321    372   **
   322    373   ** This command can be used to track third party software.
   323    374   **
   324         -**
   325    375   ** SUMMARY: fossil addremove
   326         -** Options: ?--dotfiles? ?--ignore GLOBPATTERN? ?--test?
          376  +** Options: ?--dotfiles? ?--ignore GLOB? ?--test? ?--case-sensitive BOOL?
   327    377   */
   328         -void import_cmd(void){
          378  +void addremove_cmd(void){
   329    379     Blob path;
   330    380     const char *zIgnoreFlag = find_option("ignore",0,1);
   331    381     int allFlag = find_option("dotfiles",0,0)!=0;
   332    382     int isTest = find_option("test",0,0)!=0;
          383  +  int caseSensitive;
   333    384     int n;
   334    385     Stmt q;
   335    386     int vid;
   336    387     int nAdd = 0;
   337    388     int nDelete = 0;
   338    389     Glob *pIgnore;
   339    390   
          391  +  capture_case_sensitive_option();
   340    392     db_must_be_within_tree();
          393  +  caseSensitive = filenames_are_case_sensitive();
   341    394     if( zIgnoreFlag==0 ){
   342    395       zIgnoreFlag = db_get_versionable_setting("ignore-glob", 0);
   343    396     }
   344    397     vid = db_lget_int("checkout",0);
   345    398     if( vid==0 ){
   346    399       fossil_panic("no checkout to add to");
   347    400     }
................................................................................
   356    409     db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
   357    410     n = strlen(g.zLocalRoot);
   358    411     blob_init(&path, g.zLocalRoot, n-1);
   359    412     /* now we read the complete file structure into a temp table */
   360    413     pIgnore = glob_create(zIgnoreFlag);
   361    414     vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
   362    415     glob_free(pIgnore);
   363         -  nAdd = add_files_in_sfile(vid);
          416  +  nAdd = add_files_in_sfile(vid, caseSensitive);
   364    417   
   365    418     /* step 2: search for missing files */
   366    419     db_prepare(&q,
   367    420         "SELECT pathname, %Q || pathname, deleted FROM vfile"
   368    421         " WHERE NOT deleted"
   369    422         " ORDER BY 1",
   370    423         g.zLocalRoot

Changes to src/cgi.c.

   293    293     }
   294    294   
   295    295     if( blob_size(&extraHeader)>0 ){
   296    296       fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
   297    297     }
   298    298   
   299    299     /* Add headers to turn on useful security options in browsers. */
   300         -  fprintf(g.httpOut, "X-Frame-Options: DENY\r\n");
          300  +  fprintf(g.httpOut, "X-Frame-Options: SAMEORIGIN\r\n");
   301    301     /* This stops fossil pages appearing in frames or iframes, preventing
   302    302     ** click-jacking attacks on supporting browsers.
   303    303     **
   304    304     ** Other good headers would be
   305    305     **   Strict-Transport-Security: max-age=62208000
   306    306     ** if we're using https. However, this would break sites which serve different
   307    307     ** content on http and https protocols. Also,

Changes to src/db.c.

   151    151   
   152    152   /*
   153    153   ** Force a rollback and shutdown the database
   154    154   */
   155    155   void db_force_rollback(void){
   156    156     int i;
   157    157     static int busy = 0;
          158  +  sqlite3_stmt *pStmt = 0;
   158    159     if( busy || g.db==0 ) return;
   159    160     busy = 1;
   160    161     undo_rollback();
          162  +  while( (pStmt = sqlite3_next_stmt(g.db,pStmt))!=0 ){
          163  +    sqlite3_reset(pStmt);
          164  +  }
   161    165     while( pAllStmt ){
   162    166       db_finalize(pAllStmt);
   163    167     }
   164    168     if( nBegin ){
   165    169       sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
   166    170       nBegin = 0;
   167    171     }
................................................................................
  1364   1368   /*
  1365   1369   ** Return true if the string zVal represents "true" (or "false").
  1366   1370   */
  1367   1371   int is_truth(const char *zVal){
  1368   1372     static const char *azOn[] = { "on", "yes", "true", "1" };
  1369   1373     int i;
  1370   1374     for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
  1371         -    if( fossil_strcmp(zVal,azOn[i])==0 ) return 1;
         1375  +    if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
  1372   1376     }
  1373   1377     return 0;
  1374   1378   }
  1375   1379   int is_false(const char *zVal){
  1376   1380     static const char *azOff[] = { "off", "no", "false", "0" };
  1377   1381     int i;
  1378   1382     for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
  1379         -    if( fossil_strcmp(zVal,azOff[i])==0 ) return 1;
         1383  +    if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
  1380   1384     }
  1381   1385     return 0;
  1382   1386   }
  1383   1387   
  1384   1388   /*
  1385   1389   ** Swap the g.db and g.dbConfig connections so that the various db_* routines
  1386   1390   ** work on the ~/.fossil database instead of on the repository database.
................................................................................
  1721   1725   struct stControlSettings const ctrlSettings[] = {
  1722   1726     { "access-log",    0,                0, 0, "off"                 },
  1723   1727     { "auto-captcha",  "autocaptcha",    0, 0, "on"                  },
  1724   1728     { "auto-shun",     0,                0, 0, "on"                  },
  1725   1729     { "autosync",      0,                0, 0, "on"                  },
  1726   1730     { "binary-glob",   0,               32, 1, ""                    },
  1727   1731     { "clearsign",     0,                0, 0, "off"                 },
         1732  +  { "case-sensitive",0,                0, 0, "on"                  },
  1728   1733     { "crnl-glob",     0,               16, 1, ""                    },
  1729   1734     { "default-perms", 0,               16, 0, "u"                   },
  1730   1735     { "diff-command",  0,               16, 0, ""                    },
  1731   1736     { "dont-push",     0,                0, 0, "off"                 },
  1732   1737     { "editor",        0,               16, 0, ""                    },
  1733   1738     { "gdiff-command", 0,               16, 0, "gdiff"               },
  1734   1739     { "gmerge-command",0,               40, 0, ""                    },
................................................................................
  1784   1789   **                     tag or branch creation.  If the value is "pullonly"
  1785   1790   **                     then only pull operations occur automatically.
  1786   1791   **                     Default: on
  1787   1792   **
  1788   1793   **    binary-glob      The VALUE is a comma or newline-separated list of
  1789   1794   **     (versionable)   GLOB patterns that should be treated as binary files
  1790   1795   **                     for merging purposes.  Example:   *.xml
         1796  +**
         1797  +**    case-sensitive   If TRUE, the files whose names differ only in case
         1798  +**                     care considered distinct.  If FALSE files whose names
         1799  +**                     differ only in case are the same file.  Defaults to
         1800  +**                     TRUE for unix and FALSE for windows and mac.
  1791   1801   **
  1792   1802   **    clearsign        When enabled, fossil will attempt to sign all commits
  1793   1803   **                     with gpg.  When disabled (the default), commits will
  1794   1804   **                     be unsigned.  Default: off
  1795   1805   **
  1796   1806   **    crnl-glob        A comma or newline-separated list of GLOB patterns for
  1797   1807   **     (versionable)   text files in which it is ok to have CR+NL line endings.

Changes to src/merge.c.

    51     51   **
    52     52   **   --binary GLOBPATTERN    Treat files that match GLOBPATTERN as binary
    53     53   **                           and do not try to merge parallel changes.  This
    54     54   **                           option overrides the "binary-glob" setting.
    55     55   **
    56     56   **   --nochange | -n         Dryrun:  do not actually make any changes; just
    57     57   **                           show what would have happened.
           58  +**
           59  +**   --case-sensitive BOOL   Overwrite the case-sensitive setting.  If false,
           60  +**                           files whose names differ only in case are taken
           61  +**                           to be the same file.
    58     62   */
    59     63   void merge_cmd(void){
    60     64     int vid;              /* Current version "V" */
    61     65     int mid;              /* Version we are merging from "M" */
    62     66     int pid;              /* The pivot version - most recent common ancestor P */
    63     67     int detailFlag;       /* True if the --detail option is present */
    64     68     int pickFlag;         /* True if the --cherrypick option is present */
................................................................................
    67     71     const char *zBinGlob; /* The value of --binary */
    68     72     const char *zPivot;   /* The value of --baseline */
    69     73     int debugFlag;        /* True if --debug is present */
    70     74     int nChng;            /* Number of file name changes */
    71     75     int *aChng;           /* An array of file name changes */
    72     76     int i;                /* Loop counter */
    73     77     int nConflict = 0;    /* Number of conflicts seen */
           78  +  int caseSensitive;    /* True for case-sensitive filenames */
    74     79     Stmt q;
    75     80   
    76     81   
    77     82     /* Notation:
    78     83     **
    79     84     **      V     The current checkout
    80     85     **      M     The version being merged in
................................................................................
    85     90     detailFlag = find_option("detail",0,0)!=0;
    86     91     pickFlag = find_option("cherrypick",0,0)!=0;
    87     92     backoutFlag = find_option("backout",0,0)!=0;
    88     93     debugFlag = find_option("debug",0,0)!=0;
    89     94     zBinGlob = find_option("binary",0,1);
    90     95     nochangeFlag = find_option("nochange","n",0)!=0;
    91     96     zPivot = find_option("baseline",0,1);
           97  +  capture_case_sensitive_option();
    92     98     if( g.argc!=3 ){
    93     99       usage("VERSION");
    94    100     }
    95    101     db_must_be_within_tree();
          102  +  caseSensitive = filenames_are_case_sensitive();
    96    103     if( zBinGlob==0 ) zBinGlob = db_get_versionable_setting("binary-glob",0);
    97    104     vid = db_lget_int("checkout", 0);
    98    105     if( vid==0 ){
    99    106       fossil_fatal("nothing is checked out");
   100    107     }
   101    108     mid = name_to_typed_rid(g.argv[2], "ci");
   102    109     if( mid==0 || !is_a_version(mid) ){
................................................................................
   148    155     ** The vfile.pathname field is used to match files against each other.  The
   149    156     ** FV table contains one row for each each unique filename in
   150    157     ** in the current checkout, the pivot, and the version being merged.
   151    158     */
   152    159     db_multi_exec(
   153    160       "DROP TABLE IF EXISTS fv;"
   154    161       "CREATE TEMP TABLE fv("
   155         -    "  fn TEXT PRIMARY KEY,"      /* The filename */
          162  +    "  fn TEXT PRIMARY KEY COLLATE %s,"  /* The filename */
   156    163       "  idv INTEGER,"              /* VFILE entry for current version */
   157    164       "  idp INTEGER,"              /* VFILE entry for the pivot */
   158    165       "  idm INTEGER,"              /* VFILE entry for version merging in */
   159    166       "  chnged BOOLEAN,"           /* True if current version has been edited */
   160    167       "  ridv INTEGER,"             /* Record ID for current version */
   161    168       "  ridp INTEGER,"             /* Record ID for pivot */
   162    169       "  ridm INTEGER,"             /* Record ID for merge */
   163    170       "  isexe BOOLEAN,"            /* Execute permission enabled */
   164    171       "  fnp TEXT,"                 /* The filename in the pivot */
   165    172       "  fnm TEXT"                  /* the filename in the merged version */
   166         -    ");"
          173  +    ");",
          174  +    caseSensitive ? "binary" : "nocase"
   167    175     );
   168    176   
   169    177     /* Add files found in V
   170    178     */
   171    179     db_multi_exec(
   172    180       "INSERT OR IGNORE"
   173    181       " INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,isexe,chnged)"

Changes to src/tar.c.

   199    199     int bHeader            /* is this a 'x' type tar header? */
   200    200   ){
   201    201     int split;
   202    202   
   203    203     /* if this is a Pax Interchange header prepend "PaxHeader/"
   204    204     ** so we can tell files apart from metadata */
   205    205     if( bHeader ){
   206         -    int n;
   207    206       blob_reset(&tball.pax);
   208    207       blob_appendf(&tball.pax, "PaxHeader/%*.*s", nName, nName, zName);
   209    208       zName = blob_buffer(&tball.pax);
   210    209       nName = blob_size(&tball.pax);
   211    210     }
   212    211   
   213    212     /* find the split position */
................................................................................
   286    285     char cType             /* Type of object.  '0'==file.  '5'==directory */
   287    286   ){
   288    287     /* set mode and modification time */
   289    288     sqlite3_snprintf(8, (char*)&tball.aHdr[100], "%07o", iMode);
   290    289     sqlite3_snprintf(12, (char*)&tball.aHdr[136], "%011o", mTime);
   291    290   
   292    291     /* see if we need to output a Pax Interchange Header */
   293         -  if( !is_iso646_name(zName, nName) ||
   294         -            !tar_split_path(zName, nName, tball.aHdr, &tball.aHdr[345]) ){
          292  +  if( !is_iso646_name(zName, nName)
          293  +   || !tar_split_path(zName, nName, (char*)tball.aHdr, (char*)&tball.aHdr[345])
          294  +  ){
   295    295       int lastPage;
   296    296       /* add a file name for interoperability with older programs */
   297         -    approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 1);
          297  +    approximate_split_path(zName, nName, (char*)tball.aHdr,
          298  +                           (char*)&tball.aHdr[345], 1);
   298    299   
   299    300       /* generate the Pax Interchange path header */
   300    301       blob_reset(&tball.pax);
   301    302       add_pax_header("path", zName, nName);
   302    303   
   303    304       /* set the header length, and write the header */
   304    305       sqlite3_snprintf(12, (char*)&tball.aHdr[124], "%011o",
................................................................................
   309    310       gzip_step(blob_buffer(&tball.pax), blob_size(&tball.pax));
   310    311       lastPage = blob_size(&tball.pax) % 512;
   311    312       if( lastPage!=0 ){
   312    313         gzip_step(tball.zSpaces, 512 - lastPage);
   313    314       }
   314    315   
   315    316       /* generate an approximate path for the regular header */
   316         -    approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 0);
          317  +    approximate_split_path(zName, nName, (char*)tball.aHdr,
          318  +                           (char*)&tball.aHdr[345], 0);
   317    319     }
   318    320     /* set the size */
   319    321     sqlite3_snprintf(12, (char*)&tball.aHdr[124], "%011o", iSize);
   320    322   
   321    323     /* write the regular header */
   322    324     cksum_and_write_header(cType);
   323    325   }

Changes to src/timeline.c.

   452    452   }
   453    453   
   454    454   /*
   455    455   ** Generate all of the necessary javascript to generate a timeline
   456    456   ** graph.
   457    457   */
   458    458   void timeline_output_graph_javascript(GraphContext *pGraph, int omitDescenders){
   459         -  if( pGraph && pGraph->nErr==0 ){
          459  +  if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
   460    460       GraphRow *pRow;
   461    461       int i;
   462    462       char cSep;
   463    463       @ <script  type="text/JavaScript">
   464    464       @ /* <![CDATA[ */
   465    465   
   466    466       /* the rowinfo[] array contains all the information needed to generate

Changes to www/build.wiki.

     1      1   <title>Building and Installing Fossil</title>
     2      2   
     3         -<p>This page describes how to build and install Fossil.  The
     4         -whole process is designed to be very easy.</p>
     5         -
     6      3   <h2>0.0 Using A Pre-compiled Binary</h2>
     7      4   
     8         -<p>You can skip steps 1.0 and 2.0 below by downloading
            5  +<p>You can skip all of the following by downloading
     9      6   a <a href="http://www.fossil-scm.org/download.html">pre-compiled binary</a>
    10         -appropriate for your platform.  If you use a pre-compiled binary
    11         -jump immediate to step 3.0.</p>
            7  +appropriate for your platform and putting that self-contained binary
            8  +someplace on your $PATH.
            9  +To uninstall, simply delete the binary.
           10  +To upgrade from an older release, just overwrite the older binary with
           11  +the newer one.</p>
           12  +
           13  +<h2>0.1 Executive Summary</h2>
           14  +
           15  +<p>Building and installing is very simple.  Three steps:</p>
           16  +
           17  +<ol>
           18  +<li> Download and unpack a source tarball or ZIP.
           19  +<li> <b>./configure; make</b>
           20  +<li> Move or copy the resulting "fossil" executable to someplace
           21  +     on your $PATH.
           22  +</ol>
           23  +
           24  +<p><hr>
    12     25   
    13     26   <h2>1.0 Obtaining The Source Code</h2>
    14     27   
    15     28   <p>Fossil is self-hosting, so you can obtain a ZIP archive containing
    16     29   a snapshot of the latest version directly from fossil's own fossil
    17     30   repository.  Follow these steps:</p>
    18     31   
................................................................................
    45     58   
    46     59   <ol>
    47     60   <li value="6">
    48     61   <p>Create a directory to hold the source code.  Then unarchive the
    49     62   ZIP or tarball you downloaded into that directory.  You should be
    50     63   in the top-level folder of that directory</p></li>
    51     64   
    52         -<li><p><b>(Optional:)</b>
    53         -Edit the Makefile to set it up like you want.  You probably do not
    54         -need to do anything.  Do not be intimidated:  There are less than 10
    55         -variables in the makefile that can be changed.  The whole Makefile
    56         -is only a few dozen lines long and most of those lines are comments.</p>
           65  +<li><i>(Optional, unix only)</i>
           66  +Run <b>./configure</b> to construct a makefile.
           67  +
           68  +<ol type="a">
           69  +<li><p>
           70  +If you do not have the OpenSSL library installed on your system, then
           71  +add <b>--with-openssl=none</b> to omit the https functionality.
           72  +
           73  +<li><p>
           74  +To build a statically linked binary (suitable for use inside a chroot
           75  +jail) add the <b>--static</b> option.
           76  +
           77  +<li><p>
           78  +Other configuration options can be seen by running
           79  +<b>./configure --help</b>
           80  +</ol>
    57     81   
    58     82   <li><p>Run make to build the "fossil" or "fossil.exe" executable.  The
    59         -details depend on your platform and compiler:
           83  +details depend on your platform and compiler.
    60     84   
    61     85   <ol type="a">
    62         -<li><p><i>Unix</i> &rarr; the default Makefile works on most unix and
    63         -unix-like systems.  Simply type "<b>make</b>".
           86  +<li><p><i>Unix</i> &rarr; the configure-generated Makefile should work on
           87  +all unix and unix-like systems.  Simply type "<b>make</b>".
           88  +
           89  +<li><p><i>Unix without running "configure"</i> &rarr; if you prefer to avoid running configure, you
           90  +can also use: <b>make -f Makefile.classic</b>.  You may want to make minor
           91  +edits to Makefile.classic to configure the build for your system.
    64     92   
    65     93   <li><p><i>Msys/MinGW</i> &rarr; Use the
    66     94   mingw makefile: "<b>make -f win/Makefile.mingw</b>"
    67     95   
    68     96   <li><p><i>VC++</i> &rarr; Use the msc makefile.  First
    69     97   change to the "win/" subdirectory ("<b>cd win</b>") then run
    70     98   "<b>nmake /f Makefile.msc</b>".

Changes to www/makefile.wiki.

   124    124   There are three preprocessors for the Fossil sources.  The mkindex
   125    125   and translate preprocessors can be run in any order.  The makeheaders
   126    126   preprocessor must be run after translate.
   127    127   
   128    128   <h2>4.1 The mkindex preprocessor</h2>
   129    129   
   130    130   The mkindex program scans the "src.c" source files looking for special
   131         -comments that identify routines that implement of various Fossil commands,
          131  +comments that identify routines that implement various Fossil commands,
   132    132   web interface methods, and help text comments.  The mkindex program
   133    133   generates some C code that Fossil uses in order to dispatch commands and
   134    134   HTTP requests and to show on-line help.  Compile the mkindex program
   135    135   from the mkindex.c source file.  Then run:
   136    136   
   137    137   <blockquote><pre>
   138    138   ./mkindex src.c >page_index.h