Fossil SCM
Improve comments
Commit
8bdd0abc7a4e95728c12103e3bbec38c911157af
Parent
758e3d318893fe5…
16 files changed
+1
-1
+2
-2
+1
-1
+41
-42
+41
-42
+16
-16
+1
-1
+35
+80
-4
+10
-10
+1
-3
+23
-23
+1
-1
+9
-9
+18
-19
+5
~
src/allrepo.c
~
src/bundle.c
~
src/fusefs.c
~
src/lookslike.c
~
src/lookslike.c
~
src/markdown.c
~
src/markdown_html.c
~
src/timeline.c
~
src/user.c
~
www/branching.wiki
~
www/copyright-release.html
~
www/fossil-v-git.wiki
~
www/index.wiki
~
www/sync.wiki
~
www/tech_overview.wiki
~
www/webpage-ex.md
+1
-1
| --- src/allrepo.c | ||
| +++ src/allrepo.c | ||
| @@ -138,11 +138,11 @@ | ||
| 138 | 138 | ** |
| 139 | 139 | ** In addition, the following maintenance operations are supported: |
| 140 | 140 | ** |
| 141 | 141 | ** add Add all the repositories named to the set of repositories |
| 142 | 142 | ** tracked by Fossil. Normally Fossil is able to keep up with |
| 143 | -** this list by itself, but sometime it can benefit from this | |
| 143 | +** this list by itself, but sometimes it can benefit from this | |
| 144 | 144 | ** hint if you rename repositories. |
| 145 | 145 | ** |
| 146 | 146 | ** ignore Arguments are repositories that should be ignored by |
| 147 | 147 | ** subsequent clean, extras, list, pull, push, rebuild, and |
| 148 | 148 | ** sync operations. The -c|--ckout option causes the listed |
| 149 | 149 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -138,11 +138,11 @@ | |
| 138 | ** |
| 139 | ** In addition, the following maintenance operations are supported: |
| 140 | ** |
| 141 | ** add Add all the repositories named to the set of repositories |
| 142 | ** tracked by Fossil. Normally Fossil is able to keep up with |
| 143 | ** this list by itself, but sometime it can benefit from this |
| 144 | ** hint if you rename repositories. |
| 145 | ** |
| 146 | ** ignore Arguments are repositories that should be ignored by |
| 147 | ** subsequent clean, extras, list, pull, push, rebuild, and |
| 148 | ** sync operations. The -c|--ckout option causes the listed |
| 149 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -138,11 +138,11 @@ | |
| 138 | ** |
| 139 | ** In addition, the following maintenance operations are supported: |
| 140 | ** |
| 141 | ** add Add all the repositories named to the set of repositories |
| 142 | ** tracked by Fossil. Normally Fossil is able to keep up with |
| 143 | ** this list by itself, but sometimes it can benefit from this |
| 144 | ** hint if you rename repositories. |
| 145 | ** |
| 146 | ** ignore Arguments are repositories that should be ignored by |
| 147 | ** subsequent clean, extras, list, pull, push, rebuild, and |
| 148 | ** sync operations. The -c|--ckout option causes the listed |
| 149 |
+2
-2
| --- src/bundle.c | ||
| +++ src/bundle.c | ||
| @@ -26,11 +26,11 @@ | ||
| 26 | 26 | ** |
| 27 | 27 | ** The bblob.delta field can be an integer, a text string, or NULL. |
| 28 | 28 | ** If an integer, then the corresponding blobid is the delta basis. |
| 29 | 29 | ** If a text string, then that string is a SHA1 hash for the delta |
| 30 | 30 | ** basis, which is presumably in the master repository. If NULL, then |
| 31 | -** data contains contain without delta compression. | |
| 31 | +** data contains content without delta compression. | |
| 32 | 32 | */ |
| 33 | 33 | static const char zBundleInit[] = |
| 34 | 34 | @ CREATE TABLE IF NOT EXISTS "%w".bconfig( |
| 35 | 35 | @ bcname TEXT, |
| 36 | 36 | @ bcvalue ANY |
| @@ -370,11 +370,11 @@ | ||
| 370 | 370 | " WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)" |
| 371 | 371 | " AND fid<%d", rid, mnToBundle); |
| 372 | 372 | } |
| 373 | 373 | } |
| 374 | 374 | |
| 375 | - /* Try to insert the insert the artifact as a delta | |
| 375 | + /* Try to insert the artifact as a delta | |
| 376 | 376 | */ |
| 377 | 377 | if( deltaFrom ){ |
| 378 | 378 | Blob basis, delta; |
| 379 | 379 | content_get(deltaFrom, &basis); |
| 380 | 380 | blob_delta_create(&basis, &content, &delta); |
| 381 | 381 |
| --- src/bundle.c | |
| +++ src/bundle.c | |
| @@ -26,11 +26,11 @@ | |
| 26 | ** |
| 27 | ** The bblob.delta field can be an integer, a text string, or NULL. |
| 28 | ** If an integer, then the corresponding blobid is the delta basis. |
| 29 | ** If a text string, then that string is a SHA1 hash for the delta |
| 30 | ** basis, which is presumably in the master repository. If NULL, then |
| 31 | ** data contains contain without delta compression. |
| 32 | */ |
| 33 | static const char zBundleInit[] = |
| 34 | @ CREATE TABLE IF NOT EXISTS "%w".bconfig( |
| 35 | @ bcname TEXT, |
| 36 | @ bcvalue ANY |
| @@ -370,11 +370,11 @@ | |
| 370 | " WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)" |
| 371 | " AND fid<%d", rid, mnToBundle); |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | /* Try to insert the insert the artifact as a delta |
| 376 | */ |
| 377 | if( deltaFrom ){ |
| 378 | Blob basis, delta; |
| 379 | content_get(deltaFrom, &basis); |
| 380 | blob_delta_create(&basis, &content, &delta); |
| 381 |
| --- src/bundle.c | |
| +++ src/bundle.c | |
| @@ -26,11 +26,11 @@ | |
| 26 | ** |
| 27 | ** The bblob.delta field can be an integer, a text string, or NULL. |
| 28 | ** If an integer, then the corresponding blobid is the delta basis. |
| 29 | ** If a text string, then that string is a SHA1 hash for the delta |
| 30 | ** basis, which is presumably in the master repository. If NULL, then |
| 31 | ** data contains content without delta compression. |
| 32 | */ |
| 33 | static const char zBundleInit[] = |
| 34 | @ CREATE TABLE IF NOT EXISTS "%w".bconfig( |
| 35 | @ bcname TEXT, |
| 36 | @ bcvalue ANY |
| @@ -370,11 +370,11 @@ | |
| 370 | " WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)" |
| 371 | " AND fid<%d", rid, mnToBundle); |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | /* Try to insert the artifact as a delta |
| 376 | */ |
| 377 | if( deltaFrom ){ |
| 378 | Blob basis, delta; |
| 379 | content_get(deltaFrom, &basis); |
| 380 | blob_delta_create(&basis, &content, &delta); |
| 381 |
+1
-1
| --- src/fusefs.c | ||
| +++ src/fusefs.c | ||
| @@ -51,11 +51,11 @@ | ||
| 51 | 51 | /* Parsed path */ |
| 52 | 52 | char *az[3]; /* 0=type, 1=id, 2=path */ |
| 53 | 53 | } fusefs; |
| 54 | 54 | |
| 55 | 55 | /* |
| 56 | -** Clear the fusefs.sz[] array. | |
| 56 | +** Clear the fusefs.az[] array. | |
| 57 | 57 | */ |
| 58 | 58 | static void fusefs_clear_path(void){ |
| 59 | 59 | int i; |
| 60 | 60 | for(i=0; i<count(fusefs.az); i++){ |
| 61 | 61 | fossil_free(fusefs.az[i]); |
| 62 | 62 |
| --- src/fusefs.c | |
| +++ src/fusefs.c | |
| @@ -51,11 +51,11 @@ | |
| 51 | /* Parsed path */ |
| 52 | char *az[3]; /* 0=type, 1=id, 2=path */ |
| 53 | } fusefs; |
| 54 | |
| 55 | /* |
| 56 | ** Clear the fusefs.sz[] array. |
| 57 | */ |
| 58 | static void fusefs_clear_path(void){ |
| 59 | int i; |
| 60 | for(i=0; i<count(fusefs.az); i++){ |
| 61 | fossil_free(fusefs.az[i]); |
| 62 |
| --- src/fusefs.c | |
| +++ src/fusefs.c | |
| @@ -51,11 +51,11 @@ | |
| 51 | /* Parsed path */ |
| 52 | char *az[3]; /* 0=type, 1=id, 2=path */ |
| 53 | } fusefs; |
| 54 | |
| 55 | /* |
| 56 | ** Clear the fusefs.az[] array. |
| 57 | */ |
| 58 | static void fusefs_clear_path(void){ |
| 59 | int i; |
| 60 | for(i=0; i<count(fusefs.az); i++){ |
| 61 | fossil_free(fusefs.az[i]); |
| 62 |
+41
-42
| --- src/lookslike.c | ||
| +++ src/lookslike.c | ||
| @@ -50,10 +50,41 @@ | ||
| 50 | 50 | #define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */ |
| 51 | 51 | #define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */ |
| 52 | 52 | #define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */ |
| 53 | 53 | #endif /* INTERFACE */ |
| 54 | 54 | |
| 55 | +/* definitions for various UTF-8 sequence lengths, encoded as start value | |
| 56 | + * and size of each valid range belonging to some lead byte*/ | |
| 57 | +#define US2A 0x80, 0x01 /* for lead byte 0xC0 */ | |
| 58 | +#define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ | |
| 59 | +#define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ | |
| 60 | +#define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ | |
| 61 | +#define US4A 0x90, 0x30 /* for lead byte 0xF0 */ | |
| 62 | +#define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ | |
| 63 | +#define US4C 0x80, 0x10 /* for lead byte 0xF4 */ | |
| 64 | +#define US0A 0x00, 0x00 /* for any other lead byte */ | |
| 65 | + | |
| 66 | +/* a table used for quick lookup of the definition that goes with a | |
| 67 | + * particular lead byte */ | |
| 68 | +static const unsigned char lb_tab[] = { | |
| 69 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 70 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 71 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 72 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 73 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 74 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 75 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 76 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 77 | + US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 78 | + US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 79 | + US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 80 | + US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 81 | + US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 82 | + US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 83 | + US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, | |
| 84 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A | |
| 85 | +}; | |
| 55 | 86 | |
| 56 | 87 | /* |
| 57 | 88 | ** This function attempts to scan each logical line within the blob to |
| 58 | 89 | ** determine the type of content it appears to contain. The return value |
| 59 | 90 | ** is a combination of one or more of the LOOK_XXX flags (see above): |
| @@ -135,54 +166,22 @@ | ||
| 135 | 166 | } |
| 136 | 167 | |
| 137 | 168 | /* |
| 138 | 169 | ** Checks for proper UTF-8. It uses the method described in: |
| 139 | 170 | ** http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences |
| 140 | -** except for the "overlong form" of \u0000 which is not considered invalid | |
| 141 | -** here: Some languages like Java and Tcl use it. This function also | |
| 142 | -** considers valid the derivatives CESU-8 & WTF-8 (as described in the | |
| 143 | -** same wikipedia article referenced previously). For UTF-8 characters | |
| 144 | -** > 7f, the variable 'c2' not necessary means the previous character. | |
| 145 | -** It's number of higher 1-bits indicate the number of continuation bytes | |
| 146 | -** that are expected to be followed. E.g. when 'c2' has a value in the range | |
| 147 | -** 0xc0..0xdf it means that 'c' is expected to contain the last continuation | |
| 148 | -** byte of a UTF-8 character. A value 0xe0..0xef means that after 'c' one | |
| 149 | -** more continuation byte is expected. | |
| 171 | +** except for the "overlong form" of \u0000 which is not considered | |
| 172 | +** invalid here: Some languages like Java and Tcl use it. This function | |
| 173 | +** also considers valid the derivatives CESU-8 & WTF-8 (as described in | |
| 174 | +** the same wikipedia article referenced previously). For UTF-8 characters | |
| 175 | +** > 0x7f, the variable 'c' not necessary means the real lead byte. | |
| 176 | +** It's number of higher 1-bits indicate the number of continuation | |
| 177 | +** bytes that are expected to be followed. E.g. when 'c' has a value | |
| 178 | +** in the range 0xc0..0xdf it means that after 'c' a single continuation | |
| 179 | +** byte is expected. A value 0xe0..0xef means that after 'c' two more | |
| 180 | +** continuation bytes are expected. | |
| 150 | 181 | */ |
| 151 | 182 | |
| 152 | -/* definitions for various UTF-8 sequence lengths, encoded as start value | |
| 153 | - * and size of each valid range belonging to some lead byte*/ | |
| 154 | -#define US2A 0x80, 0x01 /* for lead byte 0xC0 */ | |
| 155 | -#define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ | |
| 156 | -#define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ | |
| 157 | -#define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ | |
| 158 | -#define US4A 0x90, 0x30 /* for lead byte 0xF0 */ | |
| 159 | -#define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ | |
| 160 | -#define US4C 0x80, 0x10 /* for lead byte 0xF4 */ | |
| 161 | -#define US0A 0xFF, 0x00 /* for any other lead byte */ | |
| 162 | - | |
| 163 | -/* a table used for quick lookup of the definition that goes with a | |
| 164 | - * particular lead byte */ | |
| 165 | -static const unsigned char lb_tab[] = { | |
| 166 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 167 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 168 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 169 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 170 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 171 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 172 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 173 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 174 | - US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 175 | - US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 176 | - US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 177 | - US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 178 | - US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 179 | - US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 180 | - US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, | |
| 181 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A | |
| 182 | -}; | |
| 183 | - | |
| 184 | 183 | int invalid_utf8( |
| 185 | 184 | const Blob *pContent |
| 186 | 185 | ){ |
| 187 | 186 | const unsigned char *z = (unsigned char *) blob_buffer(pContent); |
| 188 | 187 | unsigned int n = blob_size(pContent); |
| 189 | 188 |
| --- src/lookslike.c | |
| +++ src/lookslike.c | |
| @@ -50,10 +50,41 @@ | |
| 50 | #define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */ |
| 51 | #define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */ |
| 52 | #define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */ |
| 53 | #endif /* INTERFACE */ |
| 54 | |
| 55 | |
| 56 | /* |
| 57 | ** This function attempts to scan each logical line within the blob to |
| 58 | ** determine the type of content it appears to contain. The return value |
| 59 | ** is a combination of one or more of the LOOK_XXX flags (see above): |
| @@ -135,54 +166,22 @@ | |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | ** Checks for proper UTF-8. It uses the method described in: |
| 139 | ** http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences |
| 140 | ** except for the "overlong form" of \u0000 which is not considered invalid |
| 141 | ** here: Some languages like Java and Tcl use it. This function also |
| 142 | ** considers valid the derivatives CESU-8 & WTF-8 (as described in the |
| 143 | ** same wikipedia article referenced previously). For UTF-8 characters |
| 144 | ** > 7f, the variable 'c2' not necessary means the previous character. |
| 145 | ** It's number of higher 1-bits indicate the number of continuation bytes |
| 146 | ** that are expected to be followed. E.g. when 'c2' has a value in the range |
| 147 | ** 0xc0..0xdf it means that 'c' is expected to contain the last continuation |
| 148 | ** byte of a UTF-8 character. A value 0xe0..0xef means that after 'c' one |
| 149 | ** more continuation byte is expected. |
| 150 | */ |
| 151 | |
| 152 | /* definitions for various UTF-8 sequence lengths, encoded as start value |
| 153 | * and size of each valid range belonging to some lead byte*/ |
| 154 | #define US2A 0x80, 0x01 /* for lead byte 0xC0 */ |
| 155 | #define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ |
| 156 | #define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ |
| 157 | #define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ |
| 158 | #define US4A 0x90, 0x30 /* for lead byte 0xF0 */ |
| 159 | #define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ |
| 160 | #define US4C 0x80, 0x10 /* for lead byte 0xF4 */ |
| 161 | #define US0A 0xFF, 0x00 /* for any other lead byte */ |
| 162 | |
| 163 | /* a table used for quick lookup of the definition that goes with a |
| 164 | * particular lead byte */ |
| 165 | static const unsigned char lb_tab[] = { |
| 166 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 167 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 168 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 169 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 170 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 171 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 172 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 173 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 174 | US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, |
| 175 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 176 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 177 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 178 | US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 179 | US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 180 | US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, |
| 181 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A |
| 182 | }; |
| 183 | |
| 184 | int invalid_utf8( |
| 185 | const Blob *pContent |
| 186 | ){ |
| 187 | const unsigned char *z = (unsigned char *) blob_buffer(pContent); |
| 188 | unsigned int n = blob_size(pContent); |
| 189 |
| --- src/lookslike.c | |
| +++ src/lookslike.c | |
| @@ -50,10 +50,41 @@ | |
| 50 | #define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */ |
| 51 | #define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */ |
| 52 | #define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */ |
| 53 | #endif /* INTERFACE */ |
| 54 | |
| 55 | /* definitions for various UTF-8 sequence lengths, encoded as start value |
| 56 | * and size of each valid range belonging to some lead byte*/ |
| 57 | #define US2A 0x80, 0x01 /* for lead byte 0xC0 */ |
| 58 | #define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ |
| 59 | #define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ |
| 60 | #define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ |
| 61 | #define US4A 0x90, 0x30 /* for lead byte 0xF0 */ |
| 62 | #define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ |
| 63 | #define US4C 0x80, 0x10 /* for lead byte 0xF4 */ |
| 64 | #define US0A 0x00, 0x00 /* for any other lead byte */ |
| 65 | |
| 66 | /* a table used for quick lookup of the definition that goes with a |
| 67 | * particular lead byte */ |
| 68 | static const unsigned char lb_tab[] = { |
| 69 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 70 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 71 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 72 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 73 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 74 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 75 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 76 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 77 | US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, |
| 78 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 79 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 80 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 81 | US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 82 | US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 83 | US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, |
| 84 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A |
| 85 | }; |
| 86 | |
| 87 | /* |
| 88 | ** This function attempts to scan each logical line within the blob to |
| 89 | ** determine the type of content it appears to contain. The return value |
| 90 | ** is a combination of one or more of the LOOK_XXX flags (see above): |
| @@ -135,54 +166,22 @@ | |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | ** Checks for proper UTF-8. It uses the method described in: |
| 170 | ** http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences |
| 171 | ** except for the "overlong form" of \u0000 which is not considered |
| 172 | ** invalid here: Some languages like Java and Tcl use it. This function |
| 173 | ** also considers valid the derivatives CESU-8 & WTF-8 (as described in |
| 174 | ** the same wikipedia article referenced previously). For UTF-8 characters |
| 175 | ** > 0x7f, the variable 'c' not necessary means the real lead byte. |
| 176 | ** It's number of higher 1-bits indicate the number of continuation |
| 177 | ** bytes that are expected to be followed. E.g. when 'c' has a value |
| 178 | ** in the range 0xc0..0xdf it means that after 'c' a single continuation |
| 179 | ** byte is expected. A value 0xe0..0xef means that after 'c' two more |
| 180 | ** continuation bytes are expected. |
| 181 | */ |
| 182 | |
| 183 | int invalid_utf8( |
| 184 | const Blob *pContent |
| 185 | ){ |
| 186 | const unsigned char *z = (unsigned char *) blob_buffer(pContent); |
| 187 | unsigned int n = blob_size(pContent); |
| 188 |
+41
-42
| --- src/lookslike.c | ||
| +++ src/lookslike.c | ||
| @@ -50,10 +50,41 @@ | ||
| 50 | 50 | #define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */ |
| 51 | 51 | #define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */ |
| 52 | 52 | #define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */ |
| 53 | 53 | #endif /* INTERFACE */ |
| 54 | 54 | |
| 55 | +/* definitions for various UTF-8 sequence lengths, encoded as start value | |
| 56 | + * and size of each valid range belonging to some lead byte*/ | |
| 57 | +#define US2A 0x80, 0x01 /* for lead byte 0xC0 */ | |
| 58 | +#define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ | |
| 59 | +#define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ | |
| 60 | +#define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ | |
| 61 | +#define US4A 0x90, 0x30 /* for lead byte 0xF0 */ | |
| 62 | +#define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ | |
| 63 | +#define US4C 0x80, 0x10 /* for lead byte 0xF4 */ | |
| 64 | +#define US0A 0x00, 0x00 /* for any other lead byte */ | |
| 65 | + | |
| 66 | +/* a table used for quick lookup of the definition that goes with a | |
| 67 | + * particular lead byte */ | |
| 68 | +static const unsigned char lb_tab[] = { | |
| 69 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 70 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 71 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 72 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 73 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 74 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 75 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 76 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 77 | + US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 78 | + US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 79 | + US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 80 | + US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 81 | + US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 82 | + US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 83 | + US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, | |
| 84 | + US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A | |
| 85 | +}; | |
| 55 | 86 | |
| 56 | 87 | /* |
| 57 | 88 | ** This function attempts to scan each logical line within the blob to |
| 58 | 89 | ** determine the type of content it appears to contain. The return value |
| 59 | 90 | ** is a combination of one or more of the LOOK_XXX flags (see above): |
| @@ -135,54 +166,22 @@ | ||
| 135 | 166 | } |
| 136 | 167 | |
| 137 | 168 | /* |
| 138 | 169 | ** Checks for proper UTF-8. It uses the method described in: |
| 139 | 170 | ** http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences |
| 140 | -** except for the "overlong form" of \u0000 which is not considered invalid | |
| 141 | -** here: Some languages like Java and Tcl use it. This function also | |
| 142 | -** considers valid the derivatives CESU-8 & WTF-8 (as described in the | |
| 143 | -** same wikipedia article referenced previously). For UTF-8 characters | |
| 144 | -** > 7f, the variable 'c2' not necessary means the previous character. | |
| 145 | -** It's number of higher 1-bits indicate the number of continuation bytes | |
| 146 | -** that are expected to be followed. E.g. when 'c2' has a value in the range | |
| 147 | -** 0xc0..0xdf it means that 'c' is expected to contain the last continuation | |
| 148 | -** byte of a UTF-8 character. A value 0xe0..0xef means that after 'c' one | |
| 149 | -** more continuation byte is expected. | |
| 171 | +** except for the "overlong form" of \u0000 which is not considered | |
| 172 | +** invalid here: Some languages like Java and Tcl use it. This function | |
| 173 | +** also considers valid the derivatives CESU-8 & WTF-8 (as described in | |
| 174 | +** the same wikipedia article referenced previously). For UTF-8 characters | |
| 175 | +** > 0x7f, the variable 'c' not necessary means the real lead byte. | |
| 176 | +** It's number of higher 1-bits indicate the number of continuation | |
| 177 | +** bytes that are expected to be followed. E.g. when 'c' has a value | |
| 178 | +** in the range 0xc0..0xdf it means that after 'c' a single continuation | |
| 179 | +** byte is expected. A value 0xe0..0xef means that after 'c' two more | |
| 180 | +** continuation bytes are expected. | |
| 150 | 181 | */ |
| 151 | 182 | |
| 152 | -/* definitions for various UTF-8 sequence lengths, encoded as start value | |
| 153 | - * and size of each valid range belonging to some lead byte*/ | |
| 154 | -#define US2A 0x80, 0x01 /* for lead byte 0xC0 */ | |
| 155 | -#define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ | |
| 156 | -#define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ | |
| 157 | -#define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ | |
| 158 | -#define US4A 0x90, 0x30 /* for lead byte 0xF0 */ | |
| 159 | -#define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ | |
| 160 | -#define US4C 0x80, 0x10 /* for lead byte 0xF4 */ | |
| 161 | -#define US0A 0xFF, 0x00 /* for any other lead byte */ | |
| 162 | - | |
| 163 | -/* a table used for quick lookup of the definition that goes with a | |
| 164 | - * particular lead byte */ | |
| 165 | -static const unsigned char lb_tab[] = { | |
| 166 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 167 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 168 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 169 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 170 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 171 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 172 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 173 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, | |
| 174 | - US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 175 | - US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 176 | - US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 177 | - US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, | |
| 178 | - US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 179 | - US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, | |
| 180 | - US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, | |
| 181 | - US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A | |
| 182 | -}; | |
| 183 | - | |
| 184 | 183 | int invalid_utf8( |
| 185 | 184 | const Blob *pContent |
| 186 | 185 | ){ |
| 187 | 186 | const unsigned char *z = (unsigned char *) blob_buffer(pContent); |
| 188 | 187 | unsigned int n = blob_size(pContent); |
| 189 | 188 |
| --- src/lookslike.c | |
| +++ src/lookslike.c | |
| @@ -50,10 +50,41 @@ | |
| 50 | #define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */ |
| 51 | #define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */ |
| 52 | #define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */ |
| 53 | #endif /* INTERFACE */ |
| 54 | |
| 55 | |
| 56 | /* |
| 57 | ** This function attempts to scan each logical line within the blob to |
| 58 | ** determine the type of content it appears to contain. The return value |
| 59 | ** is a combination of one or more of the LOOK_XXX flags (see above): |
| @@ -135,54 +166,22 @@ | |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | ** Checks for proper UTF-8. It uses the method described in: |
| 139 | ** http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences |
| 140 | ** except for the "overlong form" of \u0000 which is not considered invalid |
| 141 | ** here: Some languages like Java and Tcl use it. This function also |
| 142 | ** considers valid the derivatives CESU-8 & WTF-8 (as described in the |
| 143 | ** same wikipedia article referenced previously). For UTF-8 characters |
| 144 | ** > 7f, the variable 'c2' not necessary means the previous character. |
| 145 | ** It's number of higher 1-bits indicate the number of continuation bytes |
| 146 | ** that are expected to be followed. E.g. when 'c2' has a value in the range |
| 147 | ** 0xc0..0xdf it means that 'c' is expected to contain the last continuation |
| 148 | ** byte of a UTF-8 character. A value 0xe0..0xef means that after 'c' one |
| 149 | ** more continuation byte is expected. |
| 150 | */ |
| 151 | |
| 152 | /* definitions for various UTF-8 sequence lengths, encoded as start value |
| 153 | * and size of each valid range belonging to some lead byte*/ |
| 154 | #define US2A 0x80, 0x01 /* for lead byte 0xC0 */ |
| 155 | #define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ |
| 156 | #define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ |
| 157 | #define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ |
| 158 | #define US4A 0x90, 0x30 /* for lead byte 0xF0 */ |
| 159 | #define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ |
| 160 | #define US4C 0x80, 0x10 /* for lead byte 0xF4 */ |
| 161 | #define US0A 0xFF, 0x00 /* for any other lead byte */ |
| 162 | |
| 163 | /* a table used for quick lookup of the definition that goes with a |
| 164 | * particular lead byte */ |
| 165 | static const unsigned char lb_tab[] = { |
| 166 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 167 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 168 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 169 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 170 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 171 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 172 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 173 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 174 | US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, |
| 175 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 176 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 177 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 178 | US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 179 | US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 180 | US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, |
| 181 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A |
| 182 | }; |
| 183 | |
| 184 | int invalid_utf8( |
| 185 | const Blob *pContent |
| 186 | ){ |
| 187 | const unsigned char *z = (unsigned char *) blob_buffer(pContent); |
| 188 | unsigned int n = blob_size(pContent); |
| 189 |
| --- src/lookslike.c | |
| +++ src/lookslike.c | |
| @@ -50,10 +50,41 @@ | |
| 50 | #define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */ |
| 51 | #define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */ |
| 52 | #define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */ |
| 53 | #endif /* INTERFACE */ |
| 54 | |
| 55 | /* definitions for various UTF-8 sequence lengths, encoded as start value |
| 56 | * and size of each valid range belonging to some lead byte*/ |
| 57 | #define US2A 0x80, 0x01 /* for lead byte 0xC0 */ |
| 58 | #define US2B 0x80, 0x40 /* for lead bytes 0xC2-0xDF */ |
| 59 | #define US3A 0xA0, 0x20 /* for lead byte 0xE0 */ |
| 60 | #define US3B 0x80, 0x40 /* for lead bytes 0xE1-0xEF */ |
| 61 | #define US4A 0x90, 0x30 /* for lead byte 0xF0 */ |
| 62 | #define US4B 0x80, 0x40 /* for lead bytes 0xF1-0xF3 */ |
| 63 | #define US4C 0x80, 0x10 /* for lead byte 0xF4 */ |
| 64 | #define US0A 0x00, 0x00 /* for any other lead byte */ |
| 65 | |
| 66 | /* a table used for quick lookup of the definition that goes with a |
| 67 | * particular lead byte */ |
| 68 | static const unsigned char lb_tab[] = { |
| 69 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 70 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 71 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 72 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 73 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 74 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 75 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 76 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A, |
| 77 | US2A, US0A, US2B, US2B, US2B, US2B, US2B, US2B, |
| 78 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 79 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 80 | US2B, US2B, US2B, US2B, US2B, US2B, US2B, US2B, |
| 81 | US3A, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 82 | US3B, US3B, US3B, US3B, US3B, US3B, US3B, US3B, |
| 83 | US4A, US4B, US4B, US4B, US4C, US0A, US0A, US0A, |
| 84 | US0A, US0A, US0A, US0A, US0A, US0A, US0A, US0A |
| 85 | }; |
| 86 | |
| 87 | /* |
| 88 | ** This function attempts to scan each logical line within the blob to |
| 89 | ** determine the type of content it appears to contain. The return value |
| 90 | ** is a combination of one or more of the LOOK_XXX flags (see above): |
| @@ -135,54 +166,22 @@ | |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | ** Checks for proper UTF-8. It uses the method described in: |
| 170 | ** http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences |
| 171 | ** except for the "overlong form" of \u0000 which is not considered |
| 172 | ** invalid here: Some languages like Java and Tcl use it. This function |
| 173 | ** also considers valid the derivatives CESU-8 & WTF-8 (as described in |
| 174 | ** the same wikipedia article referenced previously). For UTF-8 characters |
| 175 | ** > 0x7f, the variable 'c' not necessary means the real lead byte. |
| 176 | ** It's number of higher 1-bits indicate the number of continuation |
| 177 | ** bytes that are expected to be followed. E.g. when 'c' has a value |
| 178 | ** in the range 0xc0..0xdf it means that after 'c' a single continuation |
| 179 | ** byte is expected. A value 0xe0..0xef means that after 'c' two more |
| 180 | ** continuation bytes are expected. |
| 181 | */ |
| 182 | |
| 183 | int invalid_utf8( |
| 184 | const Blob *pContent |
| 185 | ){ |
| 186 | const unsigned char *z = (unsigned char *) blob_buffer(pContent); |
| 187 | unsigned int n = blob_size(pContent); |
| 188 |
+16
-16
| --- src/markdown.c | ||
| +++ src/markdown.c | ||
| @@ -35,12 +35,12 @@ | ||
| 35 | 35 | #if INTERFACE |
| 36 | 36 | |
| 37 | 37 | /* mkd_autolink -- type of autolink */ |
| 38 | 38 | enum mkd_autolink { |
| 39 | 39 | MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ |
| 40 | - MKDA_NORMAL, /* normal http/http/ftp/etc link */ | |
| 41 | - MKDA_EXPLICIT_EMAIL, /* e-mail link with explit mailto: */ | |
| 40 | + MKDA_NORMAL, /* normal http/http/ftp link */ | |
| 41 | + MKDA_EXPLICIT_EMAIL, /* e-mail link with explicit mailto: */ | |
| 42 | 42 | MKDA_IMPLICIT_EMAIL /* e-mail link without mailto: */ |
| 43 | 43 | }; |
| 44 | 44 | |
| 45 | 45 | /* mkd_renderer -- functions for rendering parsed data */ |
| 46 | 46 | struct mkd_renderer { |
| @@ -348,11 +348,11 @@ | ||
| 348 | 348 | if( i>=size || data[i]!='>' || nb!=1 ) return 0; |
| 349 | 349 | return i+1; |
| 350 | 350 | } |
| 351 | 351 | |
| 352 | 352 | |
| 353 | -/* tag_length -- returns the length of the given tag, or 0 is it's not valid */ | |
| 353 | +/* tag_length -- returns the length of the given tag, or 0 if it's not valid */ | |
| 354 | 354 | static size_t tag_length(char *data, size_t size, enum mkd_autolink *autolink){ |
| 355 | 355 | size_t i, j; |
| 356 | 356 | |
| 357 | 357 | /* a valid tag can't be shorter than 3 chars */ |
| 358 | 358 | if( size<3 ) return 0; |
| @@ -403,11 +403,11 @@ | ||
| 403 | 403 | }else if( (j = is_mail_autolink(data+i, size-i))!=0 ){ |
| 404 | 404 | *autolink = (i==8) ? MKDA_EXPLICIT_EMAIL : MKDA_IMPLICIT_EMAIL; |
| 405 | 405 | return i+j; |
| 406 | 406 | } |
| 407 | 407 | |
| 408 | - /* looking for sometinhg looking like a tag end */ | |
| 408 | + /* looking for something looking like a tag end */ | |
| 409 | 409 | while( i<size && data[i]!='>' ){ i++; } |
| 410 | 410 | if( i>=size ) return 0; |
| 411 | 411 | return i+1; |
| 412 | 412 | } |
| 413 | 413 | |
| @@ -520,11 +520,11 @@ | ||
| 520 | 520 | } |
| 521 | 521 | return 0; |
| 522 | 522 | } |
| 523 | 523 | |
| 524 | 524 | |
| 525 | -/* parse_emph1 -- parsing single emphase */ | |
| 525 | +/* parse_emph1 -- parsing single emphasis */ | |
| 526 | 526 | /* closed by a symbol not preceded by whitespace and not followed by symbol */ |
| 527 | 527 | static size_t parse_emph1( |
| 528 | 528 | struct Blob *ob, |
| 529 | 529 | struct render *rndr, |
| 530 | 530 | char *data, |
| @@ -565,11 +565,11 @@ | ||
| 565 | 565 | } |
| 566 | 566 | return 0; |
| 567 | 567 | } |
| 568 | 568 | |
| 569 | 569 | |
| 570 | -/* parse_emph2 -- parsing single emphase */ | |
| 570 | +/* parse_emph2 -- parsing single emphasis */ | |
| 571 | 571 | static size_t parse_emph2( |
| 572 | 572 | struct Blob *ob, |
| 573 | 573 | struct render *rndr, |
| 574 | 574 | char *data, |
| 575 | 575 | size_t size, |
| @@ -604,11 +604,11 @@ | ||
| 604 | 604 | } |
| 605 | 605 | return 0; |
| 606 | 606 | } |
| 607 | 607 | |
| 608 | 608 | |
| 609 | -/* parse_emph3 -- parsing single emphase */ | |
| 609 | +/* parse_emph3 -- parsing single emphasis */ | |
| 610 | 610 | /* finds the first closing tag, and delegates to the other emph */ |
| 611 | 611 | static size_t parse_emph3( |
| 612 | 612 | struct Blob *ob, |
| 613 | 613 | struct render *rndr, |
| 614 | 614 | char *data, |
| @@ -777,11 +777,11 @@ | ||
| 777 | 777 | return 2; |
| 778 | 778 | } |
| 779 | 779 | |
| 780 | 780 | |
| 781 | 781 | /* char_entity -- '&' escaped when it doesn't belong to an entity */ |
| 782 | -/* valid entities are assumed to be anything mathing &#?[A-Za-z0-9]+; */ | |
| 782 | +/* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ | |
| 783 | 783 | static size_t char_entity( |
| 784 | 784 | struct Blob *ob, |
| 785 | 785 | struct render *rndr, |
| 786 | 786 | char *data, |
| 787 | 787 | size_t offset, |
| @@ -1022,11 +1022,11 @@ | ||
| 1022 | 1022 | if( i+1==id_end ){ |
| 1023 | 1023 | /* implicit id - use the contents */ |
| 1024 | 1024 | id_data = data+1; |
| 1025 | 1025 | id_size = txt_e-1; |
| 1026 | 1026 | }else{ |
| 1027 | - /* explici id - between brackets */ | |
| 1027 | + /* explicit id - between brackets */ | |
| 1028 | 1028 | id_data = data+i+1; |
| 1029 | 1029 | id_size = id_end-(i+1); |
| 1030 | 1030 | } |
| 1031 | 1031 | |
| 1032 | 1032 | if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){ |
| @@ -1138,11 +1138,11 @@ | ||
| 1138 | 1138 | |
| 1139 | 1139 | return 0; |
| 1140 | 1140 | } |
| 1141 | 1141 | |
| 1142 | 1142 | |
| 1143 | -/* is_table_sep -- returns wether there is a table separator at the given pos */ | |
| 1143 | +/* is_table_sep -- returns whether there is a table separator at pos */ | |
| 1144 | 1144 | static int is_table_sep(char *data, size_t pos){ |
| 1145 | 1145 | return data[pos]=='|' && (pos==0 || data[pos-1]!='\\'); |
| 1146 | 1146 | } |
| 1147 | 1147 | |
| 1148 | 1148 | |
| @@ -1187,11 +1187,11 @@ | ||
| 1187 | 1187 | return 0; |
| 1188 | 1188 | } |
| 1189 | 1189 | } |
| 1190 | 1190 | |
| 1191 | 1191 | |
| 1192 | -/* prefix_code -- returns prefix length for block code*/ | |
| 1192 | +/* prefix_code -- returns prefix length for block code */ | |
| 1193 | 1193 | static size_t prefix_code(char *data, size_t size){ |
| 1194 | 1194 | if( size>0 && data[0]=='\t' ) return 1; |
| 1195 | 1195 | if( size>3 && data[0]==' ' && data[1]==' ' && data[2]==' ' && data[3]==' ' ){ |
| 1196 | 1196 | return 4; |
| 1197 | 1197 | } |
| @@ -1244,11 +1244,11 @@ | ||
| 1244 | 1244 | struct render *rndr, |
| 1245 | 1245 | char *data, |
| 1246 | 1246 | size_t size); |
| 1247 | 1247 | |
| 1248 | 1248 | |
| 1249 | -/* parse_blockquote -- hanldes parsing of a blockquote fragment */ | |
| 1249 | +/* parse_blockquote -- handles parsing of a blockquote fragment */ | |
| 1250 | 1250 | static size_t parse_blockquote( |
| 1251 | 1251 | struct Blob *ob, |
| 1252 | 1252 | struct render *rndr, |
| 1253 | 1253 | char *data, |
| 1254 | 1254 | size_t size |
| @@ -1294,11 +1294,11 @@ | ||
| 1294 | 1294 | release_work_buffer(rndr, out); |
| 1295 | 1295 | return end; |
| 1296 | 1296 | } |
| 1297 | 1297 | |
| 1298 | 1298 | |
| 1299 | -/* parse_blockquote -- hanldes parsing of a regular paragraph */ | |
| 1299 | +/* parse_paragraph -- handles parsing of a regular paragraph */ | |
| 1300 | 1300 | static size_t parse_paragraph( |
| 1301 | 1301 | struct Blob *ob, |
| 1302 | 1302 | struct render *rndr, |
| 1303 | 1303 | char *data, |
| 1304 | 1304 | size_t size |
| @@ -1377,11 +1377,11 @@ | ||
| 1377 | 1377 | } |
| 1378 | 1378 | return end; |
| 1379 | 1379 | } |
| 1380 | 1380 | |
| 1381 | 1381 | |
| 1382 | -/* parse_blockquote -- hanldes parsing of a block-level code fragment */ | |
| 1382 | +/* parse_blockcode -- handles parsing of a block-level code fragment */ | |
| 1383 | 1383 | static size_t parse_blockcode( |
| 1384 | 1384 | struct Blob *ob, |
| 1385 | 1385 | struct render *rndr, |
| 1386 | 1386 | char *data, |
| 1387 | 1387 | size_t size |
| @@ -1813,11 +1813,11 @@ | ||
| 1813 | 1813 | size_t i = 0, col = 0; |
| 1814 | 1814 | size_t beg, end, total = 0; |
| 1815 | 1815 | struct Blob *cells = new_work_buffer(rndr); |
| 1816 | 1816 | int align; |
| 1817 | 1817 | |
| 1818 | - /* skip leading blanks and sperator */ | |
| 1818 | + /* skip leading blanks and separator */ | |
| 1819 | 1819 | while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; } |
| 1820 | 1820 | if( i<size && data[i]=='|' ) i++; |
| 1821 | 1821 | |
| 1822 | 1822 | /* go over all the cells */ |
| 1823 | 1823 | while( i<size && total==0 ){ |
| @@ -2030,11 +2030,11 @@ | ||
| 2030 | 2030 | static int is_ref( |
| 2031 | 2031 | char *data, /* input text */ |
| 2032 | 2032 | size_t beg, /* offset of the beginning of the line */ |
| 2033 | 2033 | size_t end, /* offset of the end of the text */ |
| 2034 | 2034 | size_t *last, /* last character of the link */ |
| 2035 | - struct Blob *refs /* arry of link references */ | |
| 2035 | + struct Blob *refs /* array of link references */ | |
| 2036 | 2036 | ){ |
| 2037 | 2037 | size_t i = 0; |
| 2038 | 2038 | size_t id_offset, id_end; |
| 2039 | 2039 | size_t link_offset, link_end; |
| 2040 | 2040 | size_t title_offset, title_end; |
| 2041 | 2041 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -35,12 +35,12 @@ | |
| 35 | #if INTERFACE |
| 36 | |
| 37 | /* mkd_autolink -- type of autolink */ |
| 38 | enum mkd_autolink { |
| 39 | MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ |
| 40 | MKDA_NORMAL, /* normal http/http/ftp/etc link */ |
| 41 | MKDA_EXPLICIT_EMAIL, /* e-mail link with explit mailto: */ |
| 42 | MKDA_IMPLICIT_EMAIL /* e-mail link without mailto: */ |
| 43 | }; |
| 44 | |
| 45 | /* mkd_renderer -- functions for rendering parsed data */ |
| 46 | struct mkd_renderer { |
| @@ -348,11 +348,11 @@ | |
| 348 | if( i>=size || data[i]!='>' || nb!=1 ) return 0; |
| 349 | return i+1; |
| 350 | } |
| 351 | |
| 352 | |
| 353 | /* tag_length -- returns the length of the given tag, or 0 is it's not valid */ |
| 354 | static size_t tag_length(char *data, size_t size, enum mkd_autolink *autolink){ |
| 355 | size_t i, j; |
| 356 | |
| 357 | /* a valid tag can't be shorter than 3 chars */ |
| 358 | if( size<3 ) return 0; |
| @@ -403,11 +403,11 @@ | |
| 403 | }else if( (j = is_mail_autolink(data+i, size-i))!=0 ){ |
| 404 | *autolink = (i==8) ? MKDA_EXPLICIT_EMAIL : MKDA_IMPLICIT_EMAIL; |
| 405 | return i+j; |
| 406 | } |
| 407 | |
| 408 | /* looking for sometinhg looking like a tag end */ |
| 409 | while( i<size && data[i]!='>' ){ i++; } |
| 410 | if( i>=size ) return 0; |
| 411 | return i+1; |
| 412 | } |
| 413 | |
| @@ -520,11 +520,11 @@ | |
| 520 | } |
| 521 | return 0; |
| 522 | } |
| 523 | |
| 524 | |
| 525 | /* parse_emph1 -- parsing single emphase */ |
| 526 | /* closed by a symbol not preceded by whitespace and not followed by symbol */ |
| 527 | static size_t parse_emph1( |
| 528 | struct Blob *ob, |
| 529 | struct render *rndr, |
| 530 | char *data, |
| @@ -565,11 +565,11 @@ | |
| 565 | } |
| 566 | return 0; |
| 567 | } |
| 568 | |
| 569 | |
| 570 | /* parse_emph2 -- parsing single emphase */ |
| 571 | static size_t parse_emph2( |
| 572 | struct Blob *ob, |
| 573 | struct render *rndr, |
| 574 | char *data, |
| 575 | size_t size, |
| @@ -604,11 +604,11 @@ | |
| 604 | } |
| 605 | return 0; |
| 606 | } |
| 607 | |
| 608 | |
| 609 | /* parse_emph3 -- parsing single emphase */ |
| 610 | /* finds the first closing tag, and delegates to the other emph */ |
| 611 | static size_t parse_emph3( |
| 612 | struct Blob *ob, |
| 613 | struct render *rndr, |
| 614 | char *data, |
| @@ -777,11 +777,11 @@ | |
| 777 | return 2; |
| 778 | } |
| 779 | |
| 780 | |
| 781 | /* char_entity -- '&' escaped when it doesn't belong to an entity */ |
| 782 | /* valid entities are assumed to be anything mathing &#?[A-Za-z0-9]+; */ |
| 783 | static size_t char_entity( |
| 784 | struct Blob *ob, |
| 785 | struct render *rndr, |
| 786 | char *data, |
| 787 | size_t offset, |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | if( i+1==id_end ){ |
| 1023 | /* implicit id - use the contents */ |
| 1024 | id_data = data+1; |
| 1025 | id_size = txt_e-1; |
| 1026 | }else{ |
| 1027 | /* explici id - between brackets */ |
| 1028 | id_data = data+i+1; |
| 1029 | id_size = id_end-(i+1); |
| 1030 | } |
| 1031 | |
| 1032 | if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){ |
| @@ -1138,11 +1138,11 @@ | |
| 1138 | |
| 1139 | return 0; |
| 1140 | } |
| 1141 | |
| 1142 | |
| 1143 | /* is_table_sep -- returns wether there is a table separator at the given pos */ |
| 1144 | static int is_table_sep(char *data, size_t pos){ |
| 1145 | return data[pos]=='|' && (pos==0 || data[pos-1]!='\\'); |
| 1146 | } |
| 1147 | |
| 1148 | |
| @@ -1187,11 +1187,11 @@ | |
| 1187 | return 0; |
| 1188 | } |
| 1189 | } |
| 1190 | |
| 1191 | |
| 1192 | /* prefix_code -- returns prefix length for block code*/ |
| 1193 | static size_t prefix_code(char *data, size_t size){ |
| 1194 | if( size>0 && data[0]=='\t' ) return 1; |
| 1195 | if( size>3 && data[0]==' ' && data[1]==' ' && data[2]==' ' && data[3]==' ' ){ |
| 1196 | return 4; |
| 1197 | } |
| @@ -1244,11 +1244,11 @@ | |
| 1244 | struct render *rndr, |
| 1245 | char *data, |
| 1246 | size_t size); |
| 1247 | |
| 1248 | |
| 1249 | /* parse_blockquote -- hanldes parsing of a blockquote fragment */ |
| 1250 | static size_t parse_blockquote( |
| 1251 | struct Blob *ob, |
| 1252 | struct render *rndr, |
| 1253 | char *data, |
| 1254 | size_t size |
| @@ -1294,11 +1294,11 @@ | |
| 1294 | release_work_buffer(rndr, out); |
| 1295 | return end; |
| 1296 | } |
| 1297 | |
| 1298 | |
| 1299 | /* parse_blockquote -- hanldes parsing of a regular paragraph */ |
| 1300 | static size_t parse_paragraph( |
| 1301 | struct Blob *ob, |
| 1302 | struct render *rndr, |
| 1303 | char *data, |
| 1304 | size_t size |
| @@ -1377,11 +1377,11 @@ | |
| 1377 | } |
| 1378 | return end; |
| 1379 | } |
| 1380 | |
| 1381 | |
| 1382 | /* parse_blockquote -- hanldes parsing of a block-level code fragment */ |
| 1383 | static size_t parse_blockcode( |
| 1384 | struct Blob *ob, |
| 1385 | struct render *rndr, |
| 1386 | char *data, |
| 1387 | size_t size |
| @@ -1813,11 +1813,11 @@ | |
| 1813 | size_t i = 0, col = 0; |
| 1814 | size_t beg, end, total = 0; |
| 1815 | struct Blob *cells = new_work_buffer(rndr); |
| 1816 | int align; |
| 1817 | |
| 1818 | /* skip leading blanks and sperator */ |
| 1819 | while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; } |
| 1820 | if( i<size && data[i]=='|' ) i++; |
| 1821 | |
| 1822 | /* go over all the cells */ |
| 1823 | while( i<size && total==0 ){ |
| @@ -2030,11 +2030,11 @@ | |
| 2030 | static int is_ref( |
| 2031 | char *data, /* input text */ |
| 2032 | size_t beg, /* offset of the beginning of the line */ |
| 2033 | size_t end, /* offset of the end of the text */ |
| 2034 | size_t *last, /* last character of the link */ |
| 2035 | struct Blob *refs /* arry of link references */ |
| 2036 | ){ |
| 2037 | size_t i = 0; |
| 2038 | size_t id_offset, id_end; |
| 2039 | size_t link_offset, link_end; |
| 2040 | size_t title_offset, title_end; |
| 2041 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -35,12 +35,12 @@ | |
| 35 | #if INTERFACE |
| 36 | |
| 37 | /* mkd_autolink -- type of autolink */ |
| 38 | enum mkd_autolink { |
| 39 | MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ |
| 40 | MKDA_NORMAL, /* normal http/http/ftp link */ |
| 41 | MKDA_EXPLICIT_EMAIL, /* e-mail link with explicit mailto: */ |
| 42 | MKDA_IMPLICIT_EMAIL /* e-mail link without mailto: */ |
| 43 | }; |
| 44 | |
| 45 | /* mkd_renderer -- functions for rendering parsed data */ |
| 46 | struct mkd_renderer { |
| @@ -348,11 +348,11 @@ | |
| 348 | if( i>=size || data[i]!='>' || nb!=1 ) return 0; |
| 349 | return i+1; |
| 350 | } |
| 351 | |
| 352 | |
| 353 | /* tag_length -- returns the length of the given tag, or 0 if it's not valid */ |
| 354 | static size_t tag_length(char *data, size_t size, enum mkd_autolink *autolink){ |
| 355 | size_t i, j; |
| 356 | |
| 357 | /* a valid tag can't be shorter than 3 chars */ |
| 358 | if( size<3 ) return 0; |
| @@ -403,11 +403,11 @@ | |
| 403 | }else if( (j = is_mail_autolink(data+i, size-i))!=0 ){ |
| 404 | *autolink = (i==8) ? MKDA_EXPLICIT_EMAIL : MKDA_IMPLICIT_EMAIL; |
| 405 | return i+j; |
| 406 | } |
| 407 | |
| 408 | /* looking for something looking like a tag end */ |
| 409 | while( i<size && data[i]!='>' ){ i++; } |
| 410 | if( i>=size ) return 0; |
| 411 | return i+1; |
| 412 | } |
| 413 | |
| @@ -520,11 +520,11 @@ | |
| 520 | } |
| 521 | return 0; |
| 522 | } |
| 523 | |
| 524 | |
| 525 | /* parse_emph1 -- parsing single emphasis */ |
| 526 | /* closed by a symbol not preceded by whitespace and not followed by symbol */ |
| 527 | static size_t parse_emph1( |
| 528 | struct Blob *ob, |
| 529 | struct render *rndr, |
| 530 | char *data, |
| @@ -565,11 +565,11 @@ | |
| 565 | } |
| 566 | return 0; |
| 567 | } |
| 568 | |
| 569 | |
| 570 | /* parse_emph2 -- parsing single emphasis */ |
| 571 | static size_t parse_emph2( |
| 572 | struct Blob *ob, |
| 573 | struct render *rndr, |
| 574 | char *data, |
| 575 | size_t size, |
| @@ -604,11 +604,11 @@ | |
| 604 | } |
| 605 | return 0; |
| 606 | } |
| 607 | |
| 608 | |
| 609 | /* parse_emph3 -- parsing single emphasis */ |
| 610 | /* finds the first closing tag, and delegates to the other emph */ |
| 611 | static size_t parse_emph3( |
| 612 | struct Blob *ob, |
| 613 | struct render *rndr, |
| 614 | char *data, |
| @@ -777,11 +777,11 @@ | |
| 777 | return 2; |
| 778 | } |
| 779 | |
| 780 | |
| 781 | /* char_entity -- '&' escaped when it doesn't belong to an entity */ |
| 782 | /* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ |
| 783 | static size_t char_entity( |
| 784 | struct Blob *ob, |
| 785 | struct render *rndr, |
| 786 | char *data, |
| 787 | size_t offset, |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | if( i+1==id_end ){ |
| 1023 | /* implicit id - use the contents */ |
| 1024 | id_data = data+1; |
| 1025 | id_size = txt_e-1; |
| 1026 | }else{ |
| 1027 | /* explicit id - between brackets */ |
| 1028 | id_data = data+i+1; |
| 1029 | id_size = id_end-(i+1); |
| 1030 | } |
| 1031 | |
| 1032 | if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){ |
| @@ -1138,11 +1138,11 @@ | |
| 1138 | |
| 1139 | return 0; |
| 1140 | } |
| 1141 | |
| 1142 | |
| 1143 | /* is_table_sep -- returns whether there is a table separator at pos */ |
| 1144 | static int is_table_sep(char *data, size_t pos){ |
| 1145 | return data[pos]=='|' && (pos==0 || data[pos-1]!='\\'); |
| 1146 | } |
| 1147 | |
| 1148 | |
| @@ -1187,11 +1187,11 @@ | |
| 1187 | return 0; |
| 1188 | } |
| 1189 | } |
| 1190 | |
| 1191 | |
| 1192 | /* prefix_code -- returns prefix length for block code */ |
| 1193 | static size_t prefix_code(char *data, size_t size){ |
| 1194 | if( size>0 && data[0]=='\t' ) return 1; |
| 1195 | if( size>3 && data[0]==' ' && data[1]==' ' && data[2]==' ' && data[3]==' ' ){ |
| 1196 | return 4; |
| 1197 | } |
| @@ -1244,11 +1244,11 @@ | |
| 1244 | struct render *rndr, |
| 1245 | char *data, |
| 1246 | size_t size); |
| 1247 | |
| 1248 | |
| 1249 | /* parse_blockquote -- handles parsing of a blockquote fragment */ |
| 1250 | static size_t parse_blockquote( |
| 1251 | struct Blob *ob, |
| 1252 | struct render *rndr, |
| 1253 | char *data, |
| 1254 | size_t size |
| @@ -1294,11 +1294,11 @@ | |
| 1294 | release_work_buffer(rndr, out); |
| 1295 | return end; |
| 1296 | } |
| 1297 | |
| 1298 | |
| 1299 | /* parse_paragraph -- handles parsing of a regular paragraph */ |
| 1300 | static size_t parse_paragraph( |
| 1301 | struct Blob *ob, |
| 1302 | struct render *rndr, |
| 1303 | char *data, |
| 1304 | size_t size |
| @@ -1377,11 +1377,11 @@ | |
| 1377 | } |
| 1378 | return end; |
| 1379 | } |
| 1380 | |
| 1381 | |
| 1382 | /* parse_blockcode -- handles parsing of a block-level code fragment */ |
| 1383 | static size_t parse_blockcode( |
| 1384 | struct Blob *ob, |
| 1385 | struct render *rndr, |
| 1386 | char *data, |
| 1387 | size_t size |
| @@ -1813,11 +1813,11 @@ | |
| 1813 | size_t i = 0, col = 0; |
| 1814 | size_t beg, end, total = 0; |
| 1815 | struct Blob *cells = new_work_buffer(rndr); |
| 1816 | int align; |
| 1817 | |
| 1818 | /* skip leading blanks and separator */ |
| 1819 | while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; } |
| 1820 | if( i<size && data[i]=='|' ) i++; |
| 1821 | |
| 1822 | /* go over all the cells */ |
| 1823 | while( i<size && total==0 ){ |
| @@ -2030,11 +2030,11 @@ | |
| 2030 | static int is_ref( |
| 2031 | char *data, /* input text */ |
| 2032 | size_t beg, /* offset of the beginning of the line */ |
| 2033 | size_t end, /* offset of the end of the text */ |
| 2034 | size_t *last, /* last character of the link */ |
| 2035 | struct Blob *refs /* array of link references */ |
| 2036 | ){ |
| 2037 | size_t i = 0; |
| 2038 | size_t id_offset, id_end; |
| 2039 | size_t link_offset, link_end; |
| 2040 | size_t title_offset, title_end; |
| 2041 |
+1
-1
| --- src/markdown_html.c | ||
| +++ src/markdown_html.c | ||
| @@ -357,11 +357,11 @@ | ||
| 357 | 357 | struct Blob *content, |
| 358 | 358 | void *opaque |
| 359 | 359 | ){ |
| 360 | 360 | char *zLink = blob_buffer(link); |
| 361 | 361 | BLOB_APPEND_LITERAL(ob, "<a href=\""); |
| 362 | - if( zLink[0]=='/' ){ | |
| 362 | + if( zLink && zLink[0]=='/' ){ | |
| 363 | 363 | /* For any hyperlink that begins with "/", make it refer to the root |
| 364 | 364 | ** of the Fossil repository */ |
| 365 | 365 | blob_append(ob, g.zTop, -1); |
| 366 | 366 | } |
| 367 | 367 | html_escape(ob, blob_buffer(link), blob_size(link)); |
| 368 | 368 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -357,11 +357,11 @@ | |
| 357 | struct Blob *content, |
| 358 | void *opaque |
| 359 | ){ |
| 360 | char *zLink = blob_buffer(link); |
| 361 | BLOB_APPEND_LITERAL(ob, "<a href=\""); |
| 362 | if( zLink[0]=='/' ){ |
| 363 | /* For any hyperlink that begins with "/", make it refer to the root |
| 364 | ** of the Fossil repository */ |
| 365 | blob_append(ob, g.zTop, -1); |
| 366 | } |
| 367 | html_escape(ob, blob_buffer(link), blob_size(link)); |
| 368 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -357,11 +357,11 @@ | |
| 357 | struct Blob *content, |
| 358 | void *opaque |
| 359 | ){ |
| 360 | char *zLink = blob_buffer(link); |
| 361 | BLOB_APPEND_LITERAL(ob, "<a href=\""); |
| 362 | if( zLink && zLink[0]=='/' ){ |
| 363 | /* For any hyperlink that begins with "/", make it refer to the root |
| 364 | ** of the Fossil repository */ |
| 365 | blob_append(ob, g.zTop, -1); |
| 366 | } |
| 367 | html_escape(ob, blob_buffer(link), blob_size(link)); |
| 368 |
+35
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1183,10 +1183,36 @@ | ||
| 1183 | 1183 | } |
| 1184 | 1184 | if( i>2 ){ |
| 1185 | 1185 | style_submenu_multichoice("y", i/2, az, isDisabled); |
| 1186 | 1186 | } |
| 1187 | 1187 | } |
| 1188 | + | |
| 1189 | +/* | |
| 1190 | +** If the zChng string is not NULL, then it should be a comma-separated | |
| 1191 | +** list of glob patterns for filenames. Add an term to the WHERE clause | |
| 1192 | +** for the SQL statement under construction that excludes any check-in that | |
| 1193 | +** does not modify one or more files matching the globs. | |
| 1194 | +*/ | |
| 1195 | +static void addFileGlobExclusion( | |
| 1196 | + const char *zChng, /* The filename GLOB list */ | |
| 1197 | + Blob *pSql /* The SELECT statement under construction */ | |
| 1198 | +){ | |
| 1199 | + if( zChng==0 || zChng[0]==0 ) return; | |
| 1200 | + blob_append_sql(pSql," AND event.objid IN (" | |
| 1201 | + "SELECT mlink.mid FROM mlink, filename" | |
| 1202 | + " WHERE mlink.fnid=filename.fnid AND %s)", | |
| 1203 | + glob_expr("filename.name", zChng)); | |
| 1204 | +} | |
| 1205 | +static void addFileGlobDescription( | |
| 1206 | + const char *zChng, /* The filename GLOB list */ | |
| 1207 | + Blob *pDescription /* Result description */ | |
| 1208 | +){ | |
| 1209 | + if( zChng==0 || zChng[0]==0 ) return; | |
| 1210 | + blob_appendf(pDescription, " that include changes to files matching %Q", | |
| 1211 | + zChng); | |
| 1212 | +} | |
| 1213 | + | |
| 1188 | 1214 | |
| 1189 | 1215 | /* |
| 1190 | 1216 | ** WEBPAGE: timeline |
| 1191 | 1217 | ** |
| 1192 | 1218 | ** Query parameters: |
| @@ -1209,10 +1235,12 @@ | ||
| 1209 | 1235 | ** f=CHECKIN Show family (immediate parents and children) of CHECKIN |
| 1210 | 1236 | ** from=CHECKIN Path from... |
| 1211 | 1237 | ** to=CHECKIN ... to this |
| 1212 | 1238 | ** shortest ... show only the shortest path |
| 1213 | 1239 | ** uf=FILE_SHA1 Show only check-ins that contain the given file version |
| 1240 | +** chng=GLOBLIST Show only check-ins that involve changes to a file whose | |
| 1241 | +** name matches one of the comma-separate GLOBLIST. | |
| 1214 | 1242 | ** brbg Background color from branch name |
| 1215 | 1243 | ** ubg Background color from user |
| 1216 | 1244 | ** namechng Show only check-ins that have filename changes |
| 1217 | 1245 | ** forks Show only forks and their children |
| 1218 | 1246 | ** ym=YYYY-MM Show only events for the given year/month. |
| @@ -1245,10 +1273,11 @@ | ||
| 1245 | 1273 | const char *zSearch = P("s"); /* Search string */ |
| 1246 | 1274 | const char *zUses = P("uf"); /* Only show check-ins hold this file */ |
| 1247 | 1275 | const char *zYearMonth = P("ym"); /* Show check-ins for the given YYYY-MM */ |
| 1248 | 1276 | const char *zYearWeek = P("yw"); /* Check-ins for YYYY-WW (week-of-year) */ |
| 1249 | 1277 | const char *zDay = P("ymd"); /* Check-ins for the day YYYY-MM-DD */ |
| 1278 | + const char *zChng = P("chng"); /* List of GLOBs for files that changed */ | |
| 1250 | 1279 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 1251 | 1280 | int renameOnly = P("namechng")!=0; /* Show only check-ins that rename files */ |
| 1252 | 1281 | int forkOnly = PB("forks"); /* Show only forks and their children */ |
| 1253 | 1282 | int bisectOnly = PB("bisect"); /* Show the check-ins of the bisect */ |
| 1254 | 1283 | int tagid; /* Tag ID */ |
| @@ -1437,17 +1466,21 @@ | ||
| 1437 | 1466 | blob_append_sql(&sql, ",%d", p->rid); |
| 1438 | 1467 | p = p->u.pTo; |
| 1439 | 1468 | } |
| 1440 | 1469 | blob_append(&sql, ")", -1); |
| 1441 | 1470 | path_reset(); |
| 1471 | + addFileGlobExclusion(zChng, &sql); | |
| 1442 | 1472 | tmFlags |= TIMELINE_DISJOINT; |
| 1443 | 1473 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 1474 | + style_submenu_binary("v","With Files","Without Files", | |
| 1475 | + zType[0]!='a' && zType[0]!='c'); | |
| 1444 | 1476 | blob_appendf(&desc, "%d check-ins going from ", |
| 1445 | 1477 | db_int(0, "SELECT count(*) FROM timeline")); |
| 1446 | 1478 | blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom); |
| 1447 | 1479 | blob_append(&desc, " to ", -1); |
| 1448 | 1480 | blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo); |
| 1481 | + addFileGlobDescription(zChng, &desc); | |
| 1449 | 1482 | }else if( (p_rid || d_rid) && g.perm.Read ){ |
| 1450 | 1483 | /* If p= or d= is present, ignore all other parameters other than n= */ |
| 1451 | 1484 | char *zUuid; |
| 1452 | 1485 | int np, nd; |
| 1453 | 1486 | |
| @@ -1520,10 +1553,11 @@ | ||
| 1520 | 1553 | int n; |
| 1521 | 1554 | const char *zEType = "timeline item"; |
| 1522 | 1555 | char *zDate; |
| 1523 | 1556 | Blob cond; |
| 1524 | 1557 | blob_zero(&cond); |
| 1558 | + addFileGlobExclusion(zChng, &cond); | |
| 1525 | 1559 | if( zUses ){ |
| 1526 | 1560 | blob_append_sql(&cond, " AND event.objid IN usesfile "); |
| 1527 | 1561 | } |
| 1528 | 1562 | if( renameOnly ){ |
| 1529 | 1563 | blob_append_sql(&cond, " AND event.objid IN rnfile "); |
| @@ -1730,10 +1764,11 @@ | ||
| 1730 | 1764 | tmFlags |= TIMELINE_DISJOINT; |
| 1731 | 1765 | }else if( zBrName ){ |
| 1732 | 1766 | blob_appendf(&desc, " related to \"%h\"", zBrName); |
| 1733 | 1767 | tmFlags |= TIMELINE_DISJOINT; |
| 1734 | 1768 | } |
| 1769 | + addFileGlobDescription(zChng, &desc); | |
| 1735 | 1770 | if( rAfter>0.0 ){ |
| 1736 | 1771 | if( rBefore>0.0 ){ |
| 1737 | 1772 | blob_appendf(&desc, " occurring between %h and %h.<br />", |
| 1738 | 1773 | zAfter, zBefore); |
| 1739 | 1774 | }else{ |
| 1740 | 1775 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1183,10 +1183,36 @@ | |
| 1183 | } |
| 1184 | if( i>2 ){ |
| 1185 | style_submenu_multichoice("y", i/2, az, isDisabled); |
| 1186 | } |
| 1187 | } |
| 1188 | |
| 1189 | /* |
| 1190 | ** WEBPAGE: timeline |
| 1191 | ** |
| 1192 | ** Query parameters: |
| @@ -1209,10 +1235,12 @@ | |
| 1209 | ** f=CHECKIN Show family (immediate parents and children) of CHECKIN |
| 1210 | ** from=CHECKIN Path from... |
| 1211 | ** to=CHECKIN ... to this |
| 1212 | ** shortest ... show only the shortest path |
| 1213 | ** uf=FILE_SHA1 Show only check-ins that contain the given file version |
| 1214 | ** brbg Background color from branch name |
| 1215 | ** ubg Background color from user |
| 1216 | ** namechng Show only check-ins that have filename changes |
| 1217 | ** forks Show only forks and their children |
| 1218 | ** ym=YYYY-MM Show only events for the given year/month. |
| @@ -1245,10 +1273,11 @@ | |
| 1245 | const char *zSearch = P("s"); /* Search string */ |
| 1246 | const char *zUses = P("uf"); /* Only show check-ins hold this file */ |
| 1247 | const char *zYearMonth = P("ym"); /* Show check-ins for the given YYYY-MM */ |
| 1248 | const char *zYearWeek = P("yw"); /* Check-ins for YYYY-WW (week-of-year) */ |
| 1249 | const char *zDay = P("ymd"); /* Check-ins for the day YYYY-MM-DD */ |
| 1250 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 1251 | int renameOnly = P("namechng")!=0; /* Show only check-ins that rename files */ |
| 1252 | int forkOnly = PB("forks"); /* Show only forks and their children */ |
| 1253 | int bisectOnly = PB("bisect"); /* Show the check-ins of the bisect */ |
| 1254 | int tagid; /* Tag ID */ |
| @@ -1437,17 +1466,21 @@ | |
| 1437 | blob_append_sql(&sql, ",%d", p->rid); |
| 1438 | p = p->u.pTo; |
| 1439 | } |
| 1440 | blob_append(&sql, ")", -1); |
| 1441 | path_reset(); |
| 1442 | tmFlags |= TIMELINE_DISJOINT; |
| 1443 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 1444 | blob_appendf(&desc, "%d check-ins going from ", |
| 1445 | db_int(0, "SELECT count(*) FROM timeline")); |
| 1446 | blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom); |
| 1447 | blob_append(&desc, " to ", -1); |
| 1448 | blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo); |
| 1449 | }else if( (p_rid || d_rid) && g.perm.Read ){ |
| 1450 | /* If p= or d= is present, ignore all other parameters other than n= */ |
| 1451 | char *zUuid; |
| 1452 | int np, nd; |
| 1453 | |
| @@ -1520,10 +1553,11 @@ | |
| 1520 | int n; |
| 1521 | const char *zEType = "timeline item"; |
| 1522 | char *zDate; |
| 1523 | Blob cond; |
| 1524 | blob_zero(&cond); |
| 1525 | if( zUses ){ |
| 1526 | blob_append_sql(&cond, " AND event.objid IN usesfile "); |
| 1527 | } |
| 1528 | if( renameOnly ){ |
| 1529 | blob_append_sql(&cond, " AND event.objid IN rnfile "); |
| @@ -1730,10 +1764,11 @@ | |
| 1730 | tmFlags |= TIMELINE_DISJOINT; |
| 1731 | }else if( zBrName ){ |
| 1732 | blob_appendf(&desc, " related to \"%h\"", zBrName); |
| 1733 | tmFlags |= TIMELINE_DISJOINT; |
| 1734 | } |
| 1735 | if( rAfter>0.0 ){ |
| 1736 | if( rBefore>0.0 ){ |
| 1737 | blob_appendf(&desc, " occurring between %h and %h.<br />", |
| 1738 | zAfter, zBefore); |
| 1739 | }else{ |
| 1740 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1183,10 +1183,36 @@ | |
| 1183 | } |
| 1184 | if( i>2 ){ |
| 1185 | style_submenu_multichoice("y", i/2, az, isDisabled); |
| 1186 | } |
| 1187 | } |
| 1188 | |
| 1189 | /* |
| 1190 | ** If the zChng string is not NULL, then it should be a comma-separated |
| 1191 | ** list of glob patterns for filenames. Add an term to the WHERE clause |
| 1192 | ** for the SQL statement under construction that excludes any check-in that |
| 1193 | ** does not modify one or more files matching the globs. |
| 1194 | */ |
| 1195 | static void addFileGlobExclusion( |
| 1196 | const char *zChng, /* The filename GLOB list */ |
| 1197 | Blob *pSql /* The SELECT statement under construction */ |
| 1198 | ){ |
| 1199 | if( zChng==0 || zChng[0]==0 ) return; |
| 1200 | blob_append_sql(pSql," AND event.objid IN (" |
| 1201 | "SELECT mlink.mid FROM mlink, filename" |
| 1202 | " WHERE mlink.fnid=filename.fnid AND %s)", |
| 1203 | glob_expr("filename.name", zChng)); |
| 1204 | } |
| 1205 | static void addFileGlobDescription( |
| 1206 | const char *zChng, /* The filename GLOB list */ |
| 1207 | Blob *pDescription /* Result description */ |
| 1208 | ){ |
| 1209 | if( zChng==0 || zChng[0]==0 ) return; |
| 1210 | blob_appendf(pDescription, " that include changes to files matching %Q", |
| 1211 | zChng); |
| 1212 | } |
| 1213 | |
| 1214 | |
| 1215 | /* |
| 1216 | ** WEBPAGE: timeline |
| 1217 | ** |
| 1218 | ** Query parameters: |
| @@ -1209,10 +1235,12 @@ | |
| 1235 | ** f=CHECKIN Show family (immediate parents and children) of CHECKIN |
| 1236 | ** from=CHECKIN Path from... |
| 1237 | ** to=CHECKIN ... to this |
| 1238 | ** shortest ... show only the shortest path |
| 1239 | ** uf=FILE_SHA1 Show only check-ins that contain the given file version |
| 1240 | ** chng=GLOBLIST Show only check-ins that involve changes to a file whose |
| 1241 | ** name matches one of the comma-separate GLOBLIST. |
| 1242 | ** brbg Background color from branch name |
| 1243 | ** ubg Background color from user |
| 1244 | ** namechng Show only check-ins that have filename changes |
| 1245 | ** forks Show only forks and their children |
| 1246 | ** ym=YYYY-MM Show only events for the given year/month. |
| @@ -1245,10 +1273,11 @@ | |
| 1273 | const char *zSearch = P("s"); /* Search string */ |
| 1274 | const char *zUses = P("uf"); /* Only show check-ins hold this file */ |
| 1275 | const char *zYearMonth = P("ym"); /* Show check-ins for the given YYYY-MM */ |
| 1276 | const char *zYearWeek = P("yw"); /* Check-ins for YYYY-WW (week-of-year) */ |
| 1277 | const char *zDay = P("ymd"); /* Check-ins for the day YYYY-MM-DD */ |
| 1278 | const char *zChng = P("chng"); /* List of GLOBs for files that changed */ |
| 1279 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 1280 | int renameOnly = P("namechng")!=0; /* Show only check-ins that rename files */ |
| 1281 | int forkOnly = PB("forks"); /* Show only forks and their children */ |
| 1282 | int bisectOnly = PB("bisect"); /* Show the check-ins of the bisect */ |
| 1283 | int tagid; /* Tag ID */ |
| @@ -1437,17 +1466,21 @@ | |
| 1466 | blob_append_sql(&sql, ",%d", p->rid); |
| 1467 | p = p->u.pTo; |
| 1468 | } |
| 1469 | blob_append(&sql, ")", -1); |
| 1470 | path_reset(); |
| 1471 | addFileGlobExclusion(zChng, &sql); |
| 1472 | tmFlags |= TIMELINE_DISJOINT; |
| 1473 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 1474 | style_submenu_binary("v","With Files","Without Files", |
| 1475 | zType[0]!='a' && zType[0]!='c'); |
| 1476 | blob_appendf(&desc, "%d check-ins going from ", |
| 1477 | db_int(0, "SELECT count(*) FROM timeline")); |
| 1478 | blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom); |
| 1479 | blob_append(&desc, " to ", -1); |
| 1480 | blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo); |
| 1481 | addFileGlobDescription(zChng, &desc); |
| 1482 | }else if( (p_rid || d_rid) && g.perm.Read ){ |
| 1483 | /* If p= or d= is present, ignore all other parameters other than n= */ |
| 1484 | char *zUuid; |
| 1485 | int np, nd; |
| 1486 | |
| @@ -1520,10 +1553,11 @@ | |
| 1553 | int n; |
| 1554 | const char *zEType = "timeline item"; |
| 1555 | char *zDate; |
| 1556 | Blob cond; |
| 1557 | blob_zero(&cond); |
| 1558 | addFileGlobExclusion(zChng, &cond); |
| 1559 | if( zUses ){ |
| 1560 | blob_append_sql(&cond, " AND event.objid IN usesfile "); |
| 1561 | } |
| 1562 | if( renameOnly ){ |
| 1563 | blob_append_sql(&cond, " AND event.objid IN rnfile "); |
| @@ -1730,10 +1764,11 @@ | |
| 1764 | tmFlags |= TIMELINE_DISJOINT; |
| 1765 | }else if( zBrName ){ |
| 1766 | blob_appendf(&desc, " related to \"%h\"", zBrName); |
| 1767 | tmFlags |= TIMELINE_DISJOINT; |
| 1768 | } |
| 1769 | addFileGlobDescription(zChng, &desc); |
| 1770 | if( rAfter>0.0 ){ |
| 1771 | if( rBefore>0.0 ){ |
| 1772 | blob_appendf(&desc, " occurring between %h and %h.<br />", |
| 1773 | zAfter, zBefore); |
| 1774 | }else{ |
| 1775 |
+80
-4
| --- src/user.c | ||
| +++ src/user.c | ||
| @@ -97,10 +97,79 @@ | ||
| 97 | 97 | # undef popen |
| 98 | 98 | # define popen _popen |
| 99 | 99 | # undef pclose |
| 100 | 100 | # define pclose _pclose |
| 101 | 101 | #endif |
| 102 | + | |
| 103 | +/* | |
| 104 | +** Scramble substitution matrix: | |
| 105 | +*/ | |
| 106 | +static char aSubst[256]; | |
| 107 | + | |
| 108 | +/* | |
| 109 | +** Descramble the password | |
| 110 | +*/ | |
| 111 | +static void userDescramble(char *z){ | |
| 112 | + int i; | |
| 113 | + for(i=0; z[i]; i++) z[i] = aSubst[(unsigned char)z[i]]; | |
| 114 | +} | |
| 115 | + | |
| 116 | +/* Print a string in 5-letter groups */ | |
| 117 | +static void printFive(const unsigned char *z){ | |
| 118 | + int i; | |
| 119 | + for(i=0; z[i]; i++){ | |
| 120 | + if( i>0 && (i%5)==0 ) putchar(' '); | |
| 121 | + putchar(z[i]); | |
| 122 | + } | |
| 123 | + putchar('\n'); | |
| 124 | +} | |
| 125 | + | |
| 126 | +/* Return a pseudo-random integer between 0 and N-1 */ | |
| 127 | +static int randint(int N){ | |
| 128 | + unsigned char x; | |
| 129 | + assert( N<256 ); | |
| 130 | + sqlite3_randomness(1, &x); | |
| 131 | + return x % N; | |
| 132 | +} | |
| 133 | + | |
| 134 | +/* | |
| 135 | +** Generate and print a random scrambling of letters a through z (omitting x) | |
| 136 | +** and set up the aSubst[] matrix to descramble. | |
| 137 | +*/ | |
| 138 | +static void userGenerateScrambleCode(void){ | |
| 139 | + unsigned char zOrig[30]; | |
| 140 | + unsigned char zA[30]; | |
| 141 | + unsigned char zB[30]; | |
| 142 | + int nA = 25; | |
| 143 | + int nB = 0; | |
| 144 | + int i; | |
| 145 | + memcpy(zOrig, "abcdefghijklmnopqrstuvwyz", nA+1); | |
| 146 | + memcpy(zA, zOrig, nA+1); | |
| 147 | + assert( nA==(int)strlen((char*)zA) ); | |
| 148 | + for(i=0; i<sizeof(aSubst); i++) aSubst[i] = i; | |
| 149 | + printFive(zA); | |
| 150 | + while( nA>0 ){ | |
| 151 | + int x = randint(nA); | |
| 152 | + zB[nB++] = zA[x]; | |
| 153 | + zA[x] = zA[--nA]; | |
| 154 | + } | |
| 155 | + assert( nB==25 ); | |
| 156 | + zB[nB] = 0; | |
| 157 | + printFive(zB); | |
| 158 | + for(i=0; i<nB; i++) aSubst[zB[i]] = zOrig[i]; | |
| 159 | +} | |
| 160 | + | |
| 161 | +/* | |
| 162 | +** Return the value of the FOSSIL_SECURITY_LEVEL environment variable. | |
| 163 | +** Or return 0 if that variable does not exist. | |
| 164 | +*/ | |
| 165 | +int fossil_security_level(void){ | |
| 166 | + const char *zLevel = fossil_getenv("FOSSIL_SECURITY_LEVEL"); | |
| 167 | + if( zLevel==0 ) return 0; | |
| 168 | + return atoi(zLevel); | |
| 169 | +} | |
| 170 | + | |
| 102 | 171 | |
| 103 | 172 | /* |
| 104 | 173 | ** Do a single prompt for a passphrase. Store the results in the blob. |
| 105 | 174 | ** |
| 106 | 175 | ** If the FOSSIL_PWREADER environment variable is set, then it will |
| @@ -117,10 +186,11 @@ | ||
| 117 | 186 | ** on subsequent calls to this same routine. |
| 118 | 187 | */ |
| 119 | 188 | static void prompt_for_passphrase(const char *zPrompt, Blob *pPassphrase){ |
| 120 | 189 | char *z; |
| 121 | 190 | const char *zProg = fossil_getenv("FOSSIL_PWREADER"); |
| 191 | + const char *zSecure; | |
| 122 | 192 | if( zProg && zProg[0] ){ |
| 123 | 193 | static char zPass[100]; |
| 124 | 194 | Blob cmd; |
| 125 | 195 | FILE *in; |
| 126 | 196 | blob_zero(&cmd); |
| @@ -129,10 +199,16 @@ | ||
| 129 | 199 | in = popen(blob_str(&cmd), "r"); |
| 130 | 200 | fgets(zPass, sizeof(zPass), in); |
| 131 | 201 | pclose(in); |
| 132 | 202 | blob_reset(&cmd); |
| 133 | 203 | z = zPass; |
| 204 | + }else if( fossil_security_level()>=2 ){ | |
| 205 | + userGenerateScrambleCode(); | |
| 206 | + z = getpass(zPrompt); | |
| 207 | + if( z ) userDescramble(z); | |
| 208 | + printf("\033[3A\033[J"); /* Erase previous three lines */ | |
| 209 | + fflush(stdout); | |
| 134 | 210 | }else{ |
| 135 | 211 | z = getpass(zPrompt); |
| 136 | 212 | } |
| 137 | 213 | strip_string(pPassphrase, z); |
| 138 | 214 | } |
| @@ -180,10 +256,11 @@ | ||
| 180 | 256 | char c; |
| 181 | 257 | const char *old = db_get("last-sync-pw", 0); |
| 182 | 258 | if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){ |
| 183 | 259 | return 0; |
| 184 | 260 | } |
| 261 | + if( fossil_security_level()>=1 ) return 0; | |
| 185 | 262 | prompt_user("remember password (Y/n)? ", &x); |
| 186 | 263 | c = blob_str(&x)[0]; |
| 187 | 264 | blob_reset(&x); |
| 188 | 265 | return ( c!='n' && c!='N' ); |
| 189 | 266 | } |
| @@ -540,15 +617,14 @@ | ||
| 540 | 617 | style_submenu_element("Newer", "Newer entries", |
| 541 | 618 | "%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip>=n ? skip-n : 0, |
| 542 | 619 | n, y); |
| 543 | 620 | } |
| 544 | 621 | rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql)); |
| 545 | - @ <center> | |
| 546 | 622 | fLogEnabled = db_get_boolean("access-log", 0); |
| 547 | - @ <div>Access logging is %s(fLogEnabled?"on":"off"). | |
| 623 | + @ <div align="center">Access logging is %s(fLogEnabled?"on":"off"). | |
| 548 | 624 | @ (Change this on the <a href="setup_settings">settings</a> page.)</div> |
| 549 | - @ <table border="1" cellpadding="5" id='logtable'> | |
| 625 | + @ <table border="1" cellpadding="5" id="logtable" align="center"> | |
| 550 | 626 | @ <thead><tr><th width="33%%">Date</th><th width="34%%">User</th> |
| 551 | 627 | @ <th width="33%%">IP Address</th></tr></thead><tbody> |
| 552 | 628 | while( rc==SQLITE_OK && db_step(&q)==SQLITE_ROW ){ |
| 553 | 629 | const char *zName = db_column_text(&q, 0); |
| 554 | 630 | const char *zIP = db_column_text(&q, 1); |
| @@ -569,11 +645,11 @@ | ||
| 569 | 645 | } |
| 570 | 646 | if( skip>0 || cnt>n ){ |
| 571 | 647 | style_submenu_element("All", "All entries", |
| 572 | 648 | "%s/access_log?n=10000000", g.zTop); |
| 573 | 649 | } |
| 574 | - @ </tbody></table></center> | |
| 650 | + @ </tbody></table> | |
| 575 | 651 | db_finalize(&q); |
| 576 | 652 | @ <hr /> |
| 577 | 653 | @ <form method="post" action="%s(g.zTop)/access_log"> |
| 578 | 654 | @ <label><input type="checkbox" name="delold"> |
| 579 | 655 | @ Delete all but the most recent 200 entries</input></label> |
| 580 | 656 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -97,10 +97,79 @@ | |
| 97 | # undef popen |
| 98 | # define popen _popen |
| 99 | # undef pclose |
| 100 | # define pclose _pclose |
| 101 | #endif |
| 102 | |
| 103 | /* |
| 104 | ** Do a single prompt for a passphrase. Store the results in the blob. |
| 105 | ** |
| 106 | ** If the FOSSIL_PWREADER environment variable is set, then it will |
| @@ -117,10 +186,11 @@ | |
| 117 | ** on subsequent calls to this same routine. |
| 118 | */ |
| 119 | static void prompt_for_passphrase(const char *zPrompt, Blob *pPassphrase){ |
| 120 | char *z; |
| 121 | const char *zProg = fossil_getenv("FOSSIL_PWREADER"); |
| 122 | if( zProg && zProg[0] ){ |
| 123 | static char zPass[100]; |
| 124 | Blob cmd; |
| 125 | FILE *in; |
| 126 | blob_zero(&cmd); |
| @@ -129,10 +199,16 @@ | |
| 129 | in = popen(blob_str(&cmd), "r"); |
| 130 | fgets(zPass, sizeof(zPass), in); |
| 131 | pclose(in); |
| 132 | blob_reset(&cmd); |
| 133 | z = zPass; |
| 134 | }else{ |
| 135 | z = getpass(zPrompt); |
| 136 | } |
| 137 | strip_string(pPassphrase, z); |
| 138 | } |
| @@ -180,10 +256,11 @@ | |
| 180 | char c; |
| 181 | const char *old = db_get("last-sync-pw", 0); |
| 182 | if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){ |
| 183 | return 0; |
| 184 | } |
| 185 | prompt_user("remember password (Y/n)? ", &x); |
| 186 | c = blob_str(&x)[0]; |
| 187 | blob_reset(&x); |
| 188 | return ( c!='n' && c!='N' ); |
| 189 | } |
| @@ -540,15 +617,14 @@ | |
| 540 | style_submenu_element("Newer", "Newer entries", |
| 541 | "%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip>=n ? skip-n : 0, |
| 542 | n, y); |
| 543 | } |
| 544 | rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql)); |
| 545 | @ <center> |
| 546 | fLogEnabled = db_get_boolean("access-log", 0); |
| 547 | @ <div>Access logging is %s(fLogEnabled?"on":"off"). |
| 548 | @ (Change this on the <a href="setup_settings">settings</a> page.)</div> |
| 549 | @ <table border="1" cellpadding="5" id='logtable'> |
| 550 | @ <thead><tr><th width="33%%">Date</th><th width="34%%">User</th> |
| 551 | @ <th width="33%%">IP Address</th></tr></thead><tbody> |
| 552 | while( rc==SQLITE_OK && db_step(&q)==SQLITE_ROW ){ |
| 553 | const char *zName = db_column_text(&q, 0); |
| 554 | const char *zIP = db_column_text(&q, 1); |
| @@ -569,11 +645,11 @@ | |
| 569 | } |
| 570 | if( skip>0 || cnt>n ){ |
| 571 | style_submenu_element("All", "All entries", |
| 572 | "%s/access_log?n=10000000", g.zTop); |
| 573 | } |
| 574 | @ </tbody></table></center> |
| 575 | db_finalize(&q); |
| 576 | @ <hr /> |
| 577 | @ <form method="post" action="%s(g.zTop)/access_log"> |
| 578 | @ <label><input type="checkbox" name="delold"> |
| 579 | @ Delete all but the most recent 200 entries</input></label> |
| 580 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -97,10 +97,79 @@ | |
| 97 | # undef popen |
| 98 | # define popen _popen |
| 99 | # undef pclose |
| 100 | # define pclose _pclose |
| 101 | #endif |
| 102 | |
| 103 | /* |
| 104 | ** Scramble substitution matrix: |
| 105 | */ |
| 106 | static char aSubst[256]; |
| 107 | |
| 108 | /* |
| 109 | ** Descramble the password |
| 110 | */ |
| 111 | static void userDescramble(char *z){ |
| 112 | int i; |
| 113 | for(i=0; z[i]; i++) z[i] = aSubst[(unsigned char)z[i]]; |
| 114 | } |
| 115 | |
| 116 | /* Print a string in 5-letter groups */ |
| 117 | static void printFive(const unsigned char *z){ |
| 118 | int i; |
| 119 | for(i=0; z[i]; i++){ |
| 120 | if( i>0 && (i%5)==0 ) putchar(' '); |
| 121 | putchar(z[i]); |
| 122 | } |
| 123 | putchar('\n'); |
| 124 | } |
| 125 | |
| 126 | /* Return a pseudo-random integer between 0 and N-1 */ |
| 127 | static int randint(int N){ |
| 128 | unsigned char x; |
| 129 | assert( N<256 ); |
| 130 | sqlite3_randomness(1, &x); |
| 131 | return x % N; |
| 132 | } |
| 133 | |
| 134 | /* |
| 135 | ** Generate and print a random scrambling of letters a through z (omitting x) |
| 136 | ** and set up the aSubst[] matrix to descramble. |
| 137 | */ |
| 138 | static void userGenerateScrambleCode(void){ |
| 139 | unsigned char zOrig[30]; |
| 140 | unsigned char zA[30]; |
| 141 | unsigned char zB[30]; |
| 142 | int nA = 25; |
| 143 | int nB = 0; |
| 144 | int i; |
| 145 | memcpy(zOrig, "abcdefghijklmnopqrstuvwyz", nA+1); |
| 146 | memcpy(zA, zOrig, nA+1); |
| 147 | assert( nA==(int)strlen((char*)zA) ); |
| 148 | for(i=0; i<sizeof(aSubst); i++) aSubst[i] = i; |
| 149 | printFive(zA); |
| 150 | while( nA>0 ){ |
| 151 | int x = randint(nA); |
| 152 | zB[nB++] = zA[x]; |
| 153 | zA[x] = zA[--nA]; |
| 154 | } |
| 155 | assert( nB==25 ); |
| 156 | zB[nB] = 0; |
| 157 | printFive(zB); |
| 158 | for(i=0; i<nB; i++) aSubst[zB[i]] = zOrig[i]; |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | ** Return the value of the FOSSIL_SECURITY_LEVEL environment variable. |
| 163 | ** Or return 0 if that variable does not exist. |
| 164 | */ |
| 165 | int fossil_security_level(void){ |
| 166 | const char *zLevel = fossil_getenv("FOSSIL_SECURITY_LEVEL"); |
| 167 | if( zLevel==0 ) return 0; |
| 168 | return atoi(zLevel); |
| 169 | } |
| 170 | |
| 171 | |
| 172 | /* |
| 173 | ** Do a single prompt for a passphrase. Store the results in the blob. |
| 174 | ** |
| 175 | ** If the FOSSIL_PWREADER environment variable is set, then it will |
| @@ -117,10 +186,11 @@ | |
| 186 | ** on subsequent calls to this same routine. |
| 187 | */ |
| 188 | static void prompt_for_passphrase(const char *zPrompt, Blob *pPassphrase){ |
| 189 | char *z; |
| 190 | const char *zProg = fossil_getenv("FOSSIL_PWREADER"); |
| 191 | const char *zSecure; |
| 192 | if( zProg && zProg[0] ){ |
| 193 | static char zPass[100]; |
| 194 | Blob cmd; |
| 195 | FILE *in; |
| 196 | blob_zero(&cmd); |
| @@ -129,10 +199,16 @@ | |
| 199 | in = popen(blob_str(&cmd), "r"); |
| 200 | fgets(zPass, sizeof(zPass), in); |
| 201 | pclose(in); |
| 202 | blob_reset(&cmd); |
| 203 | z = zPass; |
| 204 | }else if( fossil_security_level()>=2 ){ |
| 205 | userGenerateScrambleCode(); |
| 206 | z = getpass(zPrompt); |
| 207 | if( z ) userDescramble(z); |
| 208 | printf("\033[3A\033[J"); /* Erase previous three lines */ |
| 209 | fflush(stdout); |
| 210 | }else{ |
| 211 | z = getpass(zPrompt); |
| 212 | } |
| 213 | strip_string(pPassphrase, z); |
| 214 | } |
| @@ -180,10 +256,11 @@ | |
| 256 | char c; |
| 257 | const char *old = db_get("last-sync-pw", 0); |
| 258 | if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){ |
| 259 | return 0; |
| 260 | } |
| 261 | if( fossil_security_level()>=1 ) return 0; |
| 262 | prompt_user("remember password (Y/n)? ", &x); |
| 263 | c = blob_str(&x)[0]; |
| 264 | blob_reset(&x); |
| 265 | return ( c!='n' && c!='N' ); |
| 266 | } |
| @@ -540,15 +617,14 @@ | |
| 617 | style_submenu_element("Newer", "Newer entries", |
| 618 | "%s/access_log?o=%d&n=%d&y=%d", g.zTop, skip>=n ? skip-n : 0, |
| 619 | n, y); |
| 620 | } |
| 621 | rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql)); |
| 622 | fLogEnabled = db_get_boolean("access-log", 0); |
| 623 | @ <div align="center">Access logging is %s(fLogEnabled?"on":"off"). |
| 624 | @ (Change this on the <a href="setup_settings">settings</a> page.)</div> |
| 625 | @ <table border="1" cellpadding="5" id="logtable" align="center"> |
| 626 | @ <thead><tr><th width="33%%">Date</th><th width="34%%">User</th> |
| 627 | @ <th width="33%%">IP Address</th></tr></thead><tbody> |
| 628 | while( rc==SQLITE_OK && db_step(&q)==SQLITE_ROW ){ |
| 629 | const char *zName = db_column_text(&q, 0); |
| 630 | const char *zIP = db_column_text(&q, 1); |
| @@ -569,11 +645,11 @@ | |
| 645 | } |
| 646 | if( skip>0 || cnt>n ){ |
| 647 | style_submenu_element("All", "All entries", |
| 648 | "%s/access_log?n=10000000", g.zTop); |
| 649 | } |
| 650 | @ </tbody></table> |
| 651 | db_finalize(&q); |
| 652 | @ <hr /> |
| 653 | @ <form method="post" action="%s(g.zTop)/access_log"> |
| 654 | @ <label><input type="checkbox" name="delold"> |
| 655 | @ Delete all but the most recent 200 entries</input></label> |
| 656 |
+10
-10
| --- www/branching.wiki | ||
| +++ www/branching.wiki | ||
| @@ -2,15 +2,15 @@ | ||
| 2 | 2 | <h2>Background</h2> |
| 3 | 3 | |
| 4 | 4 | In a simple and perfect world, the development of a project would proceed |
| 5 | 5 | linearly, as shown in figure 1. |
| 6 | 6 | |
| 7 | -<center><table border=1 cellpadding=10 hspace=10 vspace=10> | |
| 7 | +<table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> | |
| 8 | 8 | <tr><td align="center"> |
| 9 | 9 | <img src="branch01.gif" width=280 height=68><br> |
| 10 | 10 | Figure 1 |
| 11 | -</td></tr></table></center> | |
| 11 | +</td></tr></table> | |
| 12 | 12 | |
| 13 | 13 | Each circle represents a check-in. For the sake of clarity, the check-ins |
| 14 | 14 | are given small consecutive numbers. In a real system, of course, the |
| 15 | 15 | check-in numbers would be 40-character SHA1 hashes since it is not possible |
| 16 | 16 | to allocate collision-free sequential numbers in a distributed system. |
| @@ -38,15 +38,15 @@ | ||
| 38 | 38 | |
| 39 | 39 | Alas, reality often interferes with the simple linear development of a |
| 40 | 40 | project. Suppose two programmers make independent modifications to check-in 2. |
| 41 | 41 | After both changes are committed, the check-in graph looks like figure 2: |
| 42 | 42 | |
| 43 | -<center><table border=1 cellpadding=10 hspace=10 vspace=10> | |
| 43 | +<table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> | |
| 44 | 44 | <tr><td align="center"> |
| 45 | 45 | <img src="branch02.gif" width=210 height=140><br> |
| 46 | 46 | Figure 2 |
| 47 | -</td></tr></table></center> | |
| 47 | +</td></tr></table> | |
| 48 | 48 | |
| 49 | 49 | The graph in figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has |
| 50 | 50 | two children, check-ins 3 and 4. We call this state a <i>fork</i>. |
| 51 | 51 | |
| 52 | 52 | Fossil tries to prevent forks. Suppose two programmers named Alice and |
| @@ -77,15 +77,15 @@ | ||
| 77 | 77 | To resolve this situation, Alice can use the fossil <b>merge</b> command |
| 78 | 78 | to merge in Bob's changes in her local copy of check-in 3. Then she |
| 79 | 79 | can commit the results as check-in 5. This results in a DAG as shown |
| 80 | 80 | in figure 3. |
| 81 | 81 | |
| 82 | -<center><table border=1 cellpadding=10 hspace=10 vspace=10> | |
| 82 | +<table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> | |
| 83 | 83 | <tr><td align="center"> |
| 84 | 84 | <img src="branch03.gif" width=282 height=152><br> |
| 85 | 85 | Figure 3 |
| 86 | -</td></tr></table></center> | |
| 86 | +</td></tr></table> | |
| 87 | 87 | |
| 88 | 88 | Check-in 5 is a child of check-in 3 because it was created by editing |
| 89 | 89 | check-in 3. But check-in 5 also inherits the changes from check-in 4 by |
| 90 | 90 | virtue of the merge. So we say that check-in 5 is a <i>merge child</i> |
| 91 | 91 | of check-in 4 and that it is a <i>direct child</i> of check-in 3. |
| @@ -124,15 +124,15 @@ | ||
| 124 | 124 | When multiple leaves are desirable, we call this <i>branching</i> |
| 125 | 125 | instead of <i>forking</i>. |
| 126 | 126 | Figure 4 shows an example of a project where there are two branches, one |
| 127 | 127 | for development work and another for testing. |
| 128 | 128 | |
| 129 | -<center><table border=1 cellpadding=10 hspace=10 vspace=10> | |
| 129 | +<table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> | |
| 130 | 130 | <tr><td align="center"> |
| 131 | 131 | <img src="branch04.gif" width=426 height=123><br> |
| 132 | 132 | Figure 4 |
| 133 | -</td></tr></table></center> | |
| 133 | +</td></tr></table> | |
| 134 | 134 | |
| 135 | 135 | The hypothetical scenario of figure 4 is this: The project starts and |
| 136 | 136 | progresses to a point where (at check-in 2) |
| 137 | 137 | it is ready to enter testing for its first release. |
| 138 | 138 | In a real project, of course, there might be hundreds or thousands of |
| @@ -164,15 +164,15 @@ | ||
| 164 | 164 | |
| 165 | 165 | Tags and properties are used in fossil to help express the intent, and |
| 166 | 166 | thus to distinguish between forks and branches. Figure 5 shows the |
| 167 | 167 | same scenario as figure 4 but with tags and properties added: |
| 168 | 168 | |
| 169 | -<center><table border=1 cellpadding=10 hspace=10 vspace=10> | |
| 169 | +<table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> | |
| 170 | 170 | <tr><td align="center"> |
| 171 | 171 | <img src="branch05.gif" width=485 height=177><br> |
| 172 | 172 | Figure 5 |
| 173 | -</td></tr></table></center> | |
| 173 | +</td></tr></table> | |
| 174 | 174 | |
| 175 | 175 | A <i>tag</i> is a name that is attached to a check-in. A |
| 176 | 176 | <i>property</i> is a name/value pair. Internally, fossil implements |
| 177 | 177 | tags as properties with a NULL value. So, tags and properties really |
| 178 | 178 | are much the same thing, and henceforth we will use the word "tag" |
| 179 | 179 |
| --- www/branching.wiki | |
| +++ www/branching.wiki | |
| @@ -2,15 +2,15 @@ | |
| 2 | <h2>Background</h2> |
| 3 | |
| 4 | In a simple and perfect world, the development of a project would proceed |
| 5 | linearly, as shown in figure 1. |
| 6 | |
| 7 | <center><table border=1 cellpadding=10 hspace=10 vspace=10> |
| 8 | <tr><td align="center"> |
| 9 | <img src="branch01.gif" width=280 height=68><br> |
| 10 | Figure 1 |
| 11 | </td></tr></table></center> |
| 12 | |
| 13 | Each circle represents a check-in. For the sake of clarity, the check-ins |
| 14 | are given small consecutive numbers. In a real system, of course, the |
| 15 | check-in numbers would be 40-character SHA1 hashes since it is not possible |
| 16 | to allocate collision-free sequential numbers in a distributed system. |
| @@ -38,15 +38,15 @@ | |
| 38 | |
| 39 | Alas, reality often interferes with the simple linear development of a |
| 40 | project. Suppose two programmers make independent modifications to check-in 2. |
| 41 | After both changes are committed, the check-in graph looks like figure 2: |
| 42 | |
| 43 | <center><table border=1 cellpadding=10 hspace=10 vspace=10> |
| 44 | <tr><td align="center"> |
| 45 | <img src="branch02.gif" width=210 height=140><br> |
| 46 | Figure 2 |
| 47 | </td></tr></table></center> |
| 48 | |
| 49 | The graph in figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has |
| 50 | two children, check-ins 3 and 4. We call this state a <i>fork</i>. |
| 51 | |
| 52 | Fossil tries to prevent forks. Suppose two programmers named Alice and |
| @@ -77,15 +77,15 @@ | |
| 77 | To resolve this situation, Alice can use the fossil <b>merge</b> command |
| 78 | to merge in Bob's changes in her local copy of check-in 3. Then she |
| 79 | can commit the results as check-in 5. This results in a DAG as shown |
| 80 | in figure 3. |
| 81 | |
| 82 | <center><table border=1 cellpadding=10 hspace=10 vspace=10> |
| 83 | <tr><td align="center"> |
| 84 | <img src="branch03.gif" width=282 height=152><br> |
| 85 | Figure 3 |
| 86 | </td></tr></table></center> |
| 87 | |
| 88 | Check-in 5 is a child of check-in 3 because it was created by editing |
| 89 | check-in 3. But check-in 5 also inherits the changes from check-in 4 by |
| 90 | virtue of the merge. So we say that check-in 5 is a <i>merge child</i> |
| 91 | of check-in 4 and that it is a <i>direct child</i> of check-in 3. |
| @@ -124,15 +124,15 @@ | |
| 124 | When multiple leaves are desirable, we call this <i>branching</i> |
| 125 | instead of <i>forking</i>. |
| 126 | Figure 4 shows an example of a project where there are two branches, one |
| 127 | for development work and another for testing. |
| 128 | |
| 129 | <center><table border=1 cellpadding=10 hspace=10 vspace=10> |
| 130 | <tr><td align="center"> |
| 131 | <img src="branch04.gif" width=426 height=123><br> |
| 132 | Figure 4 |
| 133 | </td></tr></table></center> |
| 134 | |
| 135 | The hypothetical scenario of figure 4 is this: The project starts and |
| 136 | progresses to a point where (at check-in 2) |
| 137 | it is ready to enter testing for its first release. |
| 138 | In a real project, of course, there might be hundreds or thousands of |
| @@ -164,15 +164,15 @@ | |
| 164 | |
| 165 | Tags and properties are used in fossil to help express the intent, and |
| 166 | thus to distinguish between forks and branches. Figure 5 shows the |
| 167 | same scenario as figure 4 but with tags and properties added: |
| 168 | |
| 169 | <center><table border=1 cellpadding=10 hspace=10 vspace=10> |
| 170 | <tr><td align="center"> |
| 171 | <img src="branch05.gif" width=485 height=177><br> |
| 172 | Figure 5 |
| 173 | </td></tr></table></center> |
| 174 | |
| 175 | A <i>tag</i> is a name that is attached to a check-in. A |
| 176 | <i>property</i> is a name/value pair. Internally, fossil implements |
| 177 | tags as properties with a NULL value. So, tags and properties really |
| 178 | are much the same thing, and henceforth we will use the word "tag" |
| 179 |
| --- www/branching.wiki | |
| +++ www/branching.wiki | |
| @@ -2,15 +2,15 @@ | |
| 2 | <h2>Background</h2> |
| 3 | |
| 4 | In a simple and perfect world, the development of a project would proceed |
| 5 | linearly, as shown in figure 1. |
| 6 | |
| 7 | <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> |
| 8 | <tr><td align="center"> |
| 9 | <img src="branch01.gif" width=280 height=68><br> |
| 10 | Figure 1 |
| 11 | </td></tr></table> |
| 12 | |
| 13 | Each circle represents a check-in. For the sake of clarity, the check-ins |
| 14 | are given small consecutive numbers. In a real system, of course, the |
| 15 | check-in numbers would be 40-character SHA1 hashes since it is not possible |
| 16 | to allocate collision-free sequential numbers in a distributed system. |
| @@ -38,15 +38,15 @@ | |
| 38 | |
| 39 | Alas, reality often interferes with the simple linear development of a |
| 40 | project. Suppose two programmers make independent modifications to check-in 2. |
| 41 | After both changes are committed, the check-in graph looks like figure 2: |
| 42 | |
| 43 | <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> |
| 44 | <tr><td align="center"> |
| 45 | <img src="branch02.gif" width=210 height=140><br> |
| 46 | Figure 2 |
| 47 | </td></tr></table> |
| 48 | |
| 49 | The graph in figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has |
| 50 | two children, check-ins 3 and 4. We call this state a <i>fork</i>. |
| 51 | |
| 52 | Fossil tries to prevent forks. Suppose two programmers named Alice and |
| @@ -77,15 +77,15 @@ | |
| 77 | To resolve this situation, Alice can use the fossil <b>merge</b> command |
| 78 | to merge in Bob's changes in her local copy of check-in 3. Then she |
| 79 | can commit the results as check-in 5. This results in a DAG as shown |
| 80 | in figure 3. |
| 81 | |
| 82 | <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> |
| 83 | <tr><td align="center"> |
| 84 | <img src="branch03.gif" width=282 height=152><br> |
| 85 | Figure 3 |
| 86 | </td></tr></table> |
| 87 | |
| 88 | Check-in 5 is a child of check-in 3 because it was created by editing |
| 89 | check-in 3. But check-in 5 also inherits the changes from check-in 4 by |
| 90 | virtue of the merge. So we say that check-in 5 is a <i>merge child</i> |
| 91 | of check-in 4 and that it is a <i>direct child</i> of check-in 3. |
| @@ -124,15 +124,15 @@ | |
| 124 | When multiple leaves are desirable, we call this <i>branching</i> |
| 125 | instead of <i>forking</i>. |
| 126 | Figure 4 shows an example of a project where there are two branches, one |
| 127 | for development work and another for testing. |
| 128 | |
| 129 | <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> |
| 130 | <tr><td align="center"> |
| 131 | <img src="branch04.gif" width=426 height=123><br> |
| 132 | Figure 4 |
| 133 | </td></tr></table> |
| 134 | |
| 135 | The hypothetical scenario of figure 4 is this: The project starts and |
| 136 | progresses to a point where (at check-in 2) |
| 137 | it is ready to enter testing for its first release. |
| 138 | In a real project, of course, there might be hundreds or thousands of |
| @@ -164,15 +164,15 @@ | |
| 164 | |
| 165 | Tags and properties are used in fossil to help express the intent, and |
| 166 | thus to distinguish between forks and branches. Figure 5 shows the |
| 167 | same scenario as figure 4 but with tags and properties added: |
| 168 | |
| 169 | <table border=1 cellpadding=10 hspace=10 vspace=10 align="center"> |
| 170 | <tr><td align="center"> |
| 171 | <img src="branch05.gif" width=485 height=177><br> |
| 172 | Figure 5 |
| 173 | </td></tr></table> |
| 174 | |
| 175 | A <i>tag</i> is a name that is attached to a check-in. A |
| 176 | <i>property</i> is a name/value pair. Internally, fossil implements |
| 177 | tags as properties with a NULL value. So, tags and properties really |
| 178 | are much the same thing, and henceforth we will use the word "tag" |
| 179 |
+1
-3
| --- www/copyright-release.html | ||
| +++ www/copyright-release.html | ||
| @@ -74,12 +74,11 @@ | ||
| 74 | 74 | |
| 75 | 75 | <p>By filling in the following information and signing your name, |
| 76 | 76 | you agree to be bound by all of the terms |
| 77 | 77 | set forth in this agreement. Please print clearly.</p> |
| 78 | 78 | |
| 79 | -<center> | |
| 80 | -<p><table width="80%" border="1" cellpadding="0" cellspacing="0"> | |
| 79 | +<p><table width="80%" border="1" cellpadding="0" cellspacing="0" align="center"> | |
| 81 | 80 | <tr><td width="20%" valign="top">Your name & email:</td><td width="80%"> |
| 82 | 81 | |
| 83 | 82 | <!-- Replace this line with your name and email --> <p> |
| 84 | 83 | |
| 85 | 84 | </td></tr> |
| @@ -95,14 +94,13 @@ | ||
| 95 | 94 | |
| 96 | 95 | </td></tr> |
| 97 | 96 | <tr><td valign="top">Signature:</td><td> <p> </td></tr> |
| 98 | 97 | <tr><td valign="top">Date:</td><td> <p> </td></tr> |
| 99 | 98 | </table> |
| 100 | -</center> | |
| 101 | 99 | |
| 102 | 100 | <p>Send completed forms to: |
| 103 | 101 | <blockquote> |
| 104 | 102 | Hipp, Wyrick & Company, Inc.<br> |
| 105 | 103 | 6200 Maple Cove Lane<br> |
| 106 | 104 | Charlotte, NC 28269-1086<br> |
| 107 | 105 | USA |
| 108 | 106 | </p> |
| 109 | 107 |
| --- www/copyright-release.html | |
| +++ www/copyright-release.html | |
| @@ -74,12 +74,11 @@ | |
| 74 | |
| 75 | <p>By filling in the following information and signing your name, |
| 76 | you agree to be bound by all of the terms |
| 77 | set forth in this agreement. Please print clearly.</p> |
| 78 | |
| 79 | <center> |
| 80 | <p><table width="80%" border="1" cellpadding="0" cellspacing="0"> |
| 81 | <tr><td width="20%" valign="top">Your name & email:</td><td width="80%"> |
| 82 | |
| 83 | <!-- Replace this line with your name and email --> <p> |
| 84 | |
| 85 | </td></tr> |
| @@ -95,14 +94,13 @@ | |
| 95 | |
| 96 | </td></tr> |
| 97 | <tr><td valign="top">Signature:</td><td> <p> </td></tr> |
| 98 | <tr><td valign="top">Date:</td><td> <p> </td></tr> |
| 99 | </table> |
| 100 | </center> |
| 101 | |
| 102 | <p>Send completed forms to: |
| 103 | <blockquote> |
| 104 | Hipp, Wyrick & Company, Inc.<br> |
| 105 | 6200 Maple Cove Lane<br> |
| 106 | Charlotte, NC 28269-1086<br> |
| 107 | USA |
| 108 | </p> |
| 109 |
| --- www/copyright-release.html | |
| +++ www/copyright-release.html | |
| @@ -74,12 +74,11 @@ | |
| 74 | |
| 75 | <p>By filling in the following information and signing your name, |
| 76 | you agree to be bound by all of the terms |
| 77 | set forth in this agreement. Please print clearly.</p> |
| 78 | |
| 79 | <p><table width="80%" border="1" cellpadding="0" cellspacing="0" align="center"> |
| 80 | <tr><td width="20%" valign="top">Your name & email:</td><td width="80%"> |
| 81 | |
| 82 | <!-- Replace this line with your name and email --> <p> |
| 83 | |
| 84 | </td></tr> |
| @@ -95,14 +94,13 @@ | |
| 94 | |
| 95 | </td></tr> |
| 96 | <tr><td valign="top">Signature:</td><td> <p> </td></tr> |
| 97 | <tr><td valign="top">Date:</td><td> <p> </td></tr> |
| 98 | </table> |
| 99 | |
| 100 | <p>Send completed forms to: |
| 101 | <blockquote> |
| 102 | Hipp, Wyrick & Company, Inc.<br> |
| 103 | 6200 Maple Cove Lane<br> |
| 104 | Charlotte, NC 28269-1086<br> |
| 105 | USA |
| 106 | </p> |
| 107 |
+23
-23
| --- www/fossil-v-git.wiki | ||
| +++ www/fossil-v-git.wiki | ||
| @@ -19,11 +19,11 @@ | ||
| 19 | 19 | wiki, tickets, or tech-notes, so those elements will not transfer when |
| 20 | 20 | exporting from Fossil to Git.</i></small> |
| 21 | 21 | |
| 22 | 22 | <h2>2.0 Executive Summary:</h2> |
| 23 | 23 | |
| 24 | -<blockquote><center><table border=1 cellpadding=5> | |
| 24 | +<blockquote><table border=1 cellpadding=5 align=center> | |
| 25 | 25 | <tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr> |
| 26 | 26 | <tr><td>File versioning only</td> |
| 27 | 27 | <td>Versioning, Tickets, Wiki, and Technotes</td></tr> |
| 28 | 28 | <tr><td>Ad-hoc, pile-of-files key/value database</td> |
| 29 | 29 | <td>Relational SQL database</td></tr> |
| @@ -34,11 +34,11 @@ | ||
| 34 | 34 | <tr><td>One check-out per repository</td> |
| 35 | 35 | <td>Many check-outs per repository</td></tr> |
| 36 | 36 | <tr><td>Remembers what you should have done</td> |
| 37 | 37 | <td>Remembers what you actually did</td></tr> |
| 38 | 38 | <tr><td>GPL</td><td>BSD</td></tr> |
| 39 | -</table></center></blockquote> | |
| 39 | +</table></blockquote> | |
| 40 | 40 | |
| 41 | 41 | <h2>3.0 Discussion</h2> |
| 42 | 42 | |
| 43 | 43 | <h3>3.1 Feature Set</h3> |
| 44 | 44 | |
| @@ -58,11 +58,11 @@ | ||
| 58 | 58 | |
| 59 | 59 | For developers who choose to self-host projects (rather than using a |
| 60 | 60 | 3rd-party service such as GitHub) Fossil is much easier to set up, since |
| 61 | 61 | the stand-alone Fossil executable together with a 2-line CGI script |
| 62 | 62 | suffice to instantiate a full-featured developer website. To accomplish |
| 63 | -the same using Git requires locating, installing, configuring, integrating, | |
| 63 | +the same using Git requires locating, installing, configuring, integrating, | |
| 64 | 64 | and managing a wide assortment of separate tools. Standing up a developer |
| 65 | 65 | website using Fossil can be done in minutes, whereas doing the same using |
| 66 | 66 | Git requires hours or days. |
| 67 | 67 | |
| 68 | 68 | <h3>3.2 Database</h3> |
| @@ -69,13 +69,13 @@ | ||
| 69 | 69 | |
| 70 | 70 | The baseline data structures for Fossil and Git are the same (modulo |
| 71 | 71 | formatting details). Both systems store check-ins as immutable |
| 72 | 72 | objects referencing their immediate ancestors and named by their SHA1 hash. |
| 73 | 73 | |
| 74 | -The difference is that Git stores its objects as individual files | |
| 74 | +The difference is that Git stores its objects as individual files | |
| 75 | 75 | in the ".git" folder or compressed into |
| 76 | -bespoke "pack-files", whereas Fossil stores its objects in a | |
| 76 | +bespoke "pack-files", whereas Fossil stores its objects in a | |
| 77 | 77 | relational ([https://www.sqlite.org/|SQLite]) database file. To put it |
| 78 | 78 | another way, Git uses an ad-hoc pile-of-files key/value database whereas |
| 79 | 79 | Fossil uses a proven, general-purpose SQL database. This |
| 80 | 80 | difference is more than an implementation detail. It |
| 81 | 81 | has important consequences. |
| @@ -87,13 +87,13 @@ | ||
| 87 | 87 | GitHub provide this capability. With Git, if you are looking at some |
| 88 | 88 | historical check-in then you cannot ask |
| 89 | 89 | "what came next" or "what are the children of this check-in". |
| 90 | 90 | |
| 91 | 91 | Fossil, on the other hand, parses essential information about check-ins |
| 92 | -(parents, children, committers, comments, files changed, etc.) | |
| 93 | -into a relational database that can be easily | |
| 94 | -queried using concise SQL statements to find both ancestors and | |
| 92 | +(parents, children, committers, comments, files changed, etc.) | |
| 93 | +into a relational database that can be easily | |
| 94 | +queried using concise SQL statements to find both ancestors and | |
| 95 | 95 | descendents of a check-in. |
| 96 | 96 | |
| 97 | 97 | Leaf check-ins in Git that lack a "ref" become "detached", making them |
| 98 | 98 | difficult to locate and subject to garbage collection. This |
| 99 | 99 | "detached head" problem has caused untold grief for countless |
| @@ -100,11 +100,11 @@ | ||
| 100 | 100 | Git users. With Fossil, all check-ins are easily located using |
| 101 | 101 | a variety of attributes (parents, children, committer, date, full-text |
| 102 | 102 | search of the check-in comment) and so detached heads are simply not possible. |
| 103 | 103 | |
| 104 | 104 | The ease with which check-ins can be located and queried in Fossil |
| 105 | -has resulted in a huge variety of reports and status screens | |
| 105 | +has resulted in a huge variety of reports and status screens | |
| 106 | 106 | ([./webpage-ex.md|examples]) that show project state |
| 107 | 107 | in ways that help developers |
| 108 | 108 | maintain enhanced awareness and comprehension |
| 109 | 109 | and avoid errors. |
| 110 | 110 | |
| @@ -112,11 +112,11 @@ | ||
| 112 | 112 | |
| 113 | 113 | Fossil and Git promote different development styles. Git promotes a |
| 114 | 114 | "bazaar" development style in which numerous anonymous developers make |
| 115 | 115 | small and sometimes haphazard contributions. Fossil |
| 116 | 116 | promotes a "cathedral" development model in which the project is |
| 117 | -closely supervised by an highly engaged architect and implemented by | |
| 117 | +closely supervised by an highly engaged architect and implemented by | |
| 118 | 118 | a clique of developers. |
| 119 | 119 | |
| 120 | 120 | Nota Bene: This is not to say that Git cannot be used for cathedral-style |
| 121 | 121 | development or that Fossil cannot be used for bazaar-style development. |
| 122 | 122 | They can be. But those modes are not their design intent nor the their |
| @@ -164,27 +164,27 @@ | ||
| 164 | 164 | Git consists of many small tools, each doing one small part of the job, |
| 165 | 165 | which can be recombined (by experts) to perform powerful operations. |
| 166 | 166 | Git has a lot of complexity and many dependencies and requires an "installer" |
| 167 | 167 | script or program to get it running. |
| 168 | 168 | |
| 169 | -Fossil is a single self-contained stand-alone executable with hardly | |
| 170 | -any dependencies. Fossil can be (and often is) run inside a | |
| 169 | +Fossil is a single self-contained stand-alone executable with hardly | |
| 170 | +any dependencies. Fossil can be (and often is) run inside a | |
| 171 | 171 | minimally configured chroot jail. To install Fossil, |
| 172 | 172 | one merely puts the executable on $PATH. |
| 173 | 173 | |
| 174 | -The designer of Git says that the unix philosophy is to have lots of | |
| 175 | -small tools that collaborate to get the job done. The designer of | |
| 176 | -Fossil says that the unix philosophy is "it just works". Both | |
| 177 | -individuals have written their DVCSes to reflect their own view | |
| 174 | +The designer of Git says that the unix philosophy is to have lots of | |
| 175 | +small tools that collaborate to get the job done. The designer of | |
| 176 | +Fossil says that the unix philosophy is "it just works". Both | |
| 177 | +individuals have written their DVCSes to reflect their own view | |
| 178 | 178 | of the "unix philosophy". |
| 179 | 179 | |
| 180 | 180 | <h3>3.6 One vs. Many Check-outs per Repository</h3> |
| 181 | 181 | |
| 182 | 182 | A "repository" in Git is a pile-of-files in the ".git" subdirectory |
| 183 | 183 | of a single check-out. The check-out and the repository are inseperable. |
| 184 | 184 | |
| 185 | -With Fossil, a "repository" is a single SQLite database file | |
| 185 | +With Fossil, a "repository" is a single SQLite database file | |
| 186 | 186 | that can be stored anywhere. There |
| 187 | 187 | can be multiple active check-outs from the same repository, perhaps |
| 188 | 188 | open on different branches or on different snapshots of the same branch. |
| 189 | 189 | Long-running tests or builds can be running in one check-out while |
| 190 | 190 | changes are being committed in another. |
| @@ -201,27 +201,27 @@ | ||
| 201 | 201 | |
| 202 | 202 | Fossil, in contrast, puts more emphasis on recording exactly what happened, |
| 203 | 203 | including all of the messy errors, dead-ends, experimental branches, and |
| 204 | 204 | so forth. One might argue that this |
| 205 | 205 | makes the history of a Fossil project "messy". But another point of view |
| 206 | -is that this makes the history "accurate". In actual practice, the | |
| 206 | +is that this makes the history "accurate". In actual practice, the | |
| 207 | 207 | superior reporting tools available in Fossil mean that the added "mess" |
| 208 | 208 | is not a factor. |
| 209 | 209 | |
| 210 | 210 | One commentator has mused that Git records history according to |
| 211 | 211 | the victors, whereas Fossil records history as it actually happened. |
| 212 | 212 | |
| 213 | 213 | <h3>3.8 GPL vs. BSD</h3> |
| 214 | 214 | |
| 215 | -Git is covered by the GPL license whereas Fossil is covered by | |
| 215 | +Git is covered by the GPL license whereas Fossil is covered by | |
| 216 | 216 | a two-clause BSD license. |
| 217 | 217 | |
| 218 | 218 | Consider the difference between GPL and BSD licenses: GPL is designed |
| 219 | 219 | to make writing easier at the expense of making reading harder. BSD is |
| 220 | 220 | designed to make reading easier and the expense of making writing harder. |
| 221 | 221 | |
| 222 | -To a first approximation, the GPL license grants the right to read | |
| 222 | +To a first approximation, the GPL license grants the right to read | |
| 223 | 223 | source code to anyone who promises to give back enhancements. In other |
| 224 | 224 | words, the act of reading GPL source code (a prerequiste for making changes) |
| 225 | 225 | implies acceptance of the license which requires updates to be contributed |
| 226 | 226 | back under the same license. (The details are more complex, but the |
| 227 | 227 | foregoing captures the essence of the idea.) A big advantage of the GPL |
| @@ -249,11 +249,11 @@ | ||
| 249 | 249 | <h2>4.0 Missing Features</h2> |
| 250 | 250 | |
| 251 | 251 | Most of the capabilities found in Git are also available in Fossil and |
| 252 | 252 | the other way around. For example, both systems have local check-outs, |
| 253 | 253 | remote repositories, push/pull/sync, bisect capabilities, and a "stash". |
| 254 | -Both systems store project history as a directed acyclic graph (DAG) | |
| 254 | +Both systems store project history as a directed acyclic graph (DAG) | |
| 255 | 255 | of immutable check-in objects. |
| 256 | 256 | |
| 257 | 257 | But there are a few capabilities in one system that are missing from the |
| 258 | 258 | other. |
| 259 | 259 | |
| @@ -271,16 +271,16 @@ | ||
| 271 | 271 | Git only provides versioning of source code. Fossil strives to provide |
| 272 | 272 | other related configuration management services as well. |
| 273 | 273 | |
| 274 | 274 | * <b>Named branches</b> |
| 275 | 275 | |
| 276 | - Branches in Fossil have persistent names that are propagated | |
| 276 | + Branches in Fossil have persistent names that are propagated | |
| 277 | 277 | to collaborators via [/help?cmd=push|push] and [/help?cmd=pull|pull]. |
| 278 | 278 | All developers see the same name on the same branch. Git, in contrast, |
| 279 | 279 | uses only local branch names, so developers working on the |
| 280 | 280 | same project can (and frequently do) use a different name for the |
| 281 | - same branch. | |
| 281 | + same branch. | |
| 282 | 282 | |
| 283 | 283 | * <b>The [/help?cmd=all|fossil all] command</b> |
| 284 | 284 | |
| 285 | 285 | Fossil keeps track of all repositories and check-outs and allows |
| 286 | 286 | operations over all of them with a single command. For example, in |
| 287 | 287 |
| --- www/fossil-v-git.wiki | |
| +++ www/fossil-v-git.wiki | |
| @@ -19,11 +19,11 @@ | |
| 19 | wiki, tickets, or tech-notes, so those elements will not transfer when |
| 20 | exporting from Fossil to Git.</i></small> |
| 21 | |
| 22 | <h2>2.0 Executive Summary:</h2> |
| 23 | |
| 24 | <blockquote><center><table border=1 cellpadding=5> |
| 25 | <tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr> |
| 26 | <tr><td>File versioning only</td> |
| 27 | <td>Versioning, Tickets, Wiki, and Technotes</td></tr> |
| 28 | <tr><td>Ad-hoc, pile-of-files key/value database</td> |
| 29 | <td>Relational SQL database</td></tr> |
| @@ -34,11 +34,11 @@ | |
| 34 | <tr><td>One check-out per repository</td> |
| 35 | <td>Many check-outs per repository</td></tr> |
| 36 | <tr><td>Remembers what you should have done</td> |
| 37 | <td>Remembers what you actually did</td></tr> |
| 38 | <tr><td>GPL</td><td>BSD</td></tr> |
| 39 | </table></center></blockquote> |
| 40 | |
| 41 | <h2>3.0 Discussion</h2> |
| 42 | |
| 43 | <h3>3.1 Feature Set</h3> |
| 44 | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | For developers who choose to self-host projects (rather than using a |
| 60 | 3rd-party service such as GitHub) Fossil is much easier to set up, since |
| 61 | the stand-alone Fossil executable together with a 2-line CGI script |
| 62 | suffice to instantiate a full-featured developer website. To accomplish |
| 63 | the same using Git requires locating, installing, configuring, integrating, |
| 64 | and managing a wide assortment of separate tools. Standing up a developer |
| 65 | website using Fossil can be done in minutes, whereas doing the same using |
| 66 | Git requires hours or days. |
| 67 | |
| 68 | <h3>3.2 Database</h3> |
| @@ -69,13 +69,13 @@ | |
| 69 | |
| 70 | The baseline data structures for Fossil and Git are the same (modulo |
| 71 | formatting details). Both systems store check-ins as immutable |
| 72 | objects referencing their immediate ancestors and named by their SHA1 hash. |
| 73 | |
| 74 | The difference is that Git stores its objects as individual files |
| 75 | in the ".git" folder or compressed into |
| 76 | bespoke "pack-files", whereas Fossil stores its objects in a |
| 77 | relational ([https://www.sqlite.org/|SQLite]) database file. To put it |
| 78 | another way, Git uses an ad-hoc pile-of-files key/value database whereas |
| 79 | Fossil uses a proven, general-purpose SQL database. This |
| 80 | difference is more than an implementation detail. It |
| 81 | has important consequences. |
| @@ -87,13 +87,13 @@ | |
| 87 | GitHub provide this capability. With Git, if you are looking at some |
| 88 | historical check-in then you cannot ask |
| 89 | "what came next" or "what are the children of this check-in". |
| 90 | |
| 91 | Fossil, on the other hand, parses essential information about check-ins |
| 92 | (parents, children, committers, comments, files changed, etc.) |
| 93 | into a relational database that can be easily |
| 94 | queried using concise SQL statements to find both ancestors and |
| 95 | descendents of a check-in. |
| 96 | |
| 97 | Leaf check-ins in Git that lack a "ref" become "detached", making them |
| 98 | difficult to locate and subject to garbage collection. This |
| 99 | "detached head" problem has caused untold grief for countless |
| @@ -100,11 +100,11 @@ | |
| 100 | Git users. With Fossil, all check-ins are easily located using |
| 101 | a variety of attributes (parents, children, committer, date, full-text |
| 102 | search of the check-in comment) and so detached heads are simply not possible. |
| 103 | |
| 104 | The ease with which check-ins can be located and queried in Fossil |
| 105 | has resulted in a huge variety of reports and status screens |
| 106 | ([./webpage-ex.md|examples]) that show project state |
| 107 | in ways that help developers |
| 108 | maintain enhanced awareness and comprehension |
| 109 | and avoid errors. |
| 110 | |
| @@ -112,11 +112,11 @@ | |
| 112 | |
| 113 | Fossil and Git promote different development styles. Git promotes a |
| 114 | "bazaar" development style in which numerous anonymous developers make |
| 115 | small and sometimes haphazard contributions. Fossil |
| 116 | promotes a "cathedral" development model in which the project is |
| 117 | closely supervised by an highly engaged architect and implemented by |
| 118 | a clique of developers. |
| 119 | |
| 120 | Nota Bene: This is not to say that Git cannot be used for cathedral-style |
| 121 | development or that Fossil cannot be used for bazaar-style development. |
| 122 | They can be. But those modes are not their design intent nor the their |
| @@ -164,27 +164,27 @@ | |
| 164 | Git consists of many small tools, each doing one small part of the job, |
| 165 | which can be recombined (by experts) to perform powerful operations. |
| 166 | Git has a lot of complexity and many dependencies and requires an "installer" |
| 167 | script or program to get it running. |
| 168 | |
| 169 | Fossil is a single self-contained stand-alone executable with hardly |
| 170 | any dependencies. Fossil can be (and often is) run inside a |
| 171 | minimally configured chroot jail. To install Fossil, |
| 172 | one merely puts the executable on $PATH. |
| 173 | |
| 174 | The designer of Git says that the unix philosophy is to have lots of |
| 175 | small tools that collaborate to get the job done. The designer of |
| 176 | Fossil says that the unix philosophy is "it just works". Both |
| 177 | individuals have written their DVCSes to reflect their own view |
| 178 | of the "unix philosophy". |
| 179 | |
| 180 | <h3>3.6 One vs. Many Check-outs per Repository</h3> |
| 181 | |
| 182 | A "repository" in Git is a pile-of-files in the ".git" subdirectory |
| 183 | of a single check-out. The check-out and the repository are inseperable. |
| 184 | |
| 185 | With Fossil, a "repository" is a single SQLite database file |
| 186 | that can be stored anywhere. There |
| 187 | can be multiple active check-outs from the same repository, perhaps |
| 188 | open on different branches or on different snapshots of the same branch. |
| 189 | Long-running tests or builds can be running in one check-out while |
| 190 | changes are being committed in another. |
| @@ -201,27 +201,27 @@ | |
| 201 | |
| 202 | Fossil, in contrast, puts more emphasis on recording exactly what happened, |
| 203 | including all of the messy errors, dead-ends, experimental branches, and |
| 204 | so forth. One might argue that this |
| 205 | makes the history of a Fossil project "messy". But another point of view |
| 206 | is that this makes the history "accurate". In actual practice, the |
| 207 | superior reporting tools available in Fossil mean that the added "mess" |
| 208 | is not a factor. |
| 209 | |
| 210 | One commentator has mused that Git records history according to |
| 211 | the victors, whereas Fossil records history as it actually happened. |
| 212 | |
| 213 | <h3>3.8 GPL vs. BSD</h3> |
| 214 | |
| 215 | Git is covered by the GPL license whereas Fossil is covered by |
| 216 | a two-clause BSD license. |
| 217 | |
| 218 | Consider the difference between GPL and BSD licenses: GPL is designed |
| 219 | to make writing easier at the expense of making reading harder. BSD is |
| 220 | designed to make reading easier and the expense of making writing harder. |
| 221 | |
| 222 | To a first approximation, the GPL license grants the right to read |
| 223 | source code to anyone who promises to give back enhancements. In other |
| 224 | words, the act of reading GPL source code (a prerequiste for making changes) |
| 225 | implies acceptance of the license which requires updates to be contributed |
| 226 | back under the same license. (The details are more complex, but the |
| 227 | foregoing captures the essence of the idea.) A big advantage of the GPL |
| @@ -249,11 +249,11 @@ | |
| 249 | <h2>4.0 Missing Features</h2> |
| 250 | |
| 251 | Most of the capabilities found in Git are also available in Fossil and |
| 252 | the other way around. For example, both systems have local check-outs, |
| 253 | remote repositories, push/pull/sync, bisect capabilities, and a "stash". |
| 254 | Both systems store project history as a directed acyclic graph (DAG) |
| 255 | of immutable check-in objects. |
| 256 | |
| 257 | But there are a few capabilities in one system that are missing from the |
| 258 | other. |
| 259 | |
| @@ -271,16 +271,16 @@ | |
| 271 | Git only provides versioning of source code. Fossil strives to provide |
| 272 | other related configuration management services as well. |
| 273 | |
| 274 | * <b>Named branches</b> |
| 275 | |
| 276 | Branches in Fossil have persistent names that are propagated |
| 277 | to collaborators via [/help?cmd=push|push] and [/help?cmd=pull|pull]. |
| 278 | All developers see the same name on the same branch. Git, in contrast, |
| 279 | uses only local branch names, so developers working on the |
| 280 | same project can (and frequently do) use a different name for the |
| 281 | same branch. |
| 282 | |
| 283 | * <b>The [/help?cmd=all|fossil all] command</b> |
| 284 | |
| 285 | Fossil keeps track of all repositories and check-outs and allows |
| 286 | operations over all of them with a single command. For example, in |
| 287 |
| --- www/fossil-v-git.wiki | |
| +++ www/fossil-v-git.wiki | |
| @@ -19,11 +19,11 @@ | |
| 19 | wiki, tickets, or tech-notes, so those elements will not transfer when |
| 20 | exporting from Fossil to Git.</i></small> |
| 21 | |
| 22 | <h2>2.0 Executive Summary:</h2> |
| 23 | |
| 24 | <blockquote><table border=1 cellpadding=5 align=center> |
| 25 | <tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr> |
| 26 | <tr><td>File versioning only</td> |
| 27 | <td>Versioning, Tickets, Wiki, and Technotes</td></tr> |
| 28 | <tr><td>Ad-hoc, pile-of-files key/value database</td> |
| 29 | <td>Relational SQL database</td></tr> |
| @@ -34,11 +34,11 @@ | |
| 34 | <tr><td>One check-out per repository</td> |
| 35 | <td>Many check-outs per repository</td></tr> |
| 36 | <tr><td>Remembers what you should have done</td> |
| 37 | <td>Remembers what you actually did</td></tr> |
| 38 | <tr><td>GPL</td><td>BSD</td></tr> |
| 39 | </table></blockquote> |
| 40 | |
| 41 | <h2>3.0 Discussion</h2> |
| 42 | |
| 43 | <h3>3.1 Feature Set</h3> |
| 44 | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | For developers who choose to self-host projects (rather than using a |
| 60 | 3rd-party service such as GitHub) Fossil is much easier to set up, since |
| 61 | the stand-alone Fossil executable together with a 2-line CGI script |
| 62 | suffice to instantiate a full-featured developer website. To accomplish |
| 63 | the same using Git requires locating, installing, configuring, integrating, |
| 64 | and managing a wide assortment of separate tools. Standing up a developer |
| 65 | website using Fossil can be done in minutes, whereas doing the same using |
| 66 | Git requires hours or days. |
| 67 | |
| 68 | <h3>3.2 Database</h3> |
| @@ -69,13 +69,13 @@ | |
| 69 | |
| 70 | The baseline data structures for Fossil and Git are the same (modulo |
| 71 | formatting details). Both systems store check-ins as immutable |
| 72 | objects referencing their immediate ancestors and named by their SHA1 hash. |
| 73 | |
| 74 | The difference is that Git stores its objects as individual files |
| 75 | in the ".git" folder or compressed into |
| 76 | bespoke "pack-files", whereas Fossil stores its objects in a |
| 77 | relational ([https://www.sqlite.org/|SQLite]) database file. To put it |
| 78 | another way, Git uses an ad-hoc pile-of-files key/value database whereas |
| 79 | Fossil uses a proven, general-purpose SQL database. This |
| 80 | difference is more than an implementation detail. It |
| 81 | has important consequences. |
| @@ -87,13 +87,13 @@ | |
| 87 | GitHub provide this capability. With Git, if you are looking at some |
| 88 | historical check-in then you cannot ask |
| 89 | "what came next" or "what are the children of this check-in". |
| 90 | |
| 91 | Fossil, on the other hand, parses essential information about check-ins |
| 92 | (parents, children, committers, comments, files changed, etc.) |
| 93 | into a relational database that can be easily |
| 94 | queried using concise SQL statements to find both ancestors and |
| 95 | descendents of a check-in. |
| 96 | |
| 97 | Leaf check-ins in Git that lack a "ref" become "detached", making them |
| 98 | difficult to locate and subject to garbage collection. This |
| 99 | "detached head" problem has caused untold grief for countless |
| @@ -100,11 +100,11 @@ | |
| 100 | Git users. With Fossil, all check-ins are easily located using |
| 101 | a variety of attributes (parents, children, committer, date, full-text |
| 102 | search of the check-in comment) and so detached heads are simply not possible. |
| 103 | |
| 104 | The ease with which check-ins can be located and queried in Fossil |
| 105 | has resulted in a huge variety of reports and status screens |
| 106 | ([./webpage-ex.md|examples]) that show project state |
| 107 | in ways that help developers |
| 108 | maintain enhanced awareness and comprehension |
| 109 | and avoid errors. |
| 110 | |
| @@ -112,11 +112,11 @@ | |
| 112 | |
| 113 | Fossil and Git promote different development styles. Git promotes a |
| 114 | "bazaar" development style in which numerous anonymous developers make |
| 115 | small and sometimes haphazard contributions. Fossil |
| 116 | promotes a "cathedral" development model in which the project is |
| 117 | closely supervised by an highly engaged architect and implemented by |
| 118 | a clique of developers. |
| 119 | |
| 120 | Nota Bene: This is not to say that Git cannot be used for cathedral-style |
| 121 | development or that Fossil cannot be used for bazaar-style development. |
| 122 | They can be. But those modes are not their design intent nor the their |
| @@ -164,27 +164,27 @@ | |
| 164 | Git consists of many small tools, each doing one small part of the job, |
| 165 | which can be recombined (by experts) to perform powerful operations. |
| 166 | Git has a lot of complexity and many dependencies and requires an "installer" |
| 167 | script or program to get it running. |
| 168 | |
| 169 | Fossil is a single self-contained stand-alone executable with hardly |
| 170 | any dependencies. Fossil can be (and often is) run inside a |
| 171 | minimally configured chroot jail. To install Fossil, |
| 172 | one merely puts the executable on $PATH. |
| 173 | |
| 174 | The designer of Git says that the unix philosophy is to have lots of |
| 175 | small tools that collaborate to get the job done. The designer of |
| 176 | Fossil says that the unix philosophy is "it just works". Both |
| 177 | individuals have written their DVCSes to reflect their own view |
| 178 | of the "unix philosophy". |
| 179 | |
| 180 | <h3>3.6 One vs. Many Check-outs per Repository</h3> |
| 181 | |
| 182 | A "repository" in Git is a pile-of-files in the ".git" subdirectory |
| 183 | of a single check-out. The check-out and the repository are inseperable. |
| 184 | |
| 185 | With Fossil, a "repository" is a single SQLite database file |
| 186 | that can be stored anywhere. There |
| 187 | can be multiple active check-outs from the same repository, perhaps |
| 188 | open on different branches or on different snapshots of the same branch. |
| 189 | Long-running tests or builds can be running in one check-out while |
| 190 | changes are being committed in another. |
| @@ -201,27 +201,27 @@ | |
| 201 | |
| 202 | Fossil, in contrast, puts more emphasis on recording exactly what happened, |
| 203 | including all of the messy errors, dead-ends, experimental branches, and |
| 204 | so forth. One might argue that this |
| 205 | makes the history of a Fossil project "messy". But another point of view |
| 206 | is that this makes the history "accurate". In actual practice, the |
| 207 | superior reporting tools available in Fossil mean that the added "mess" |
| 208 | is not a factor. |
| 209 | |
| 210 | One commentator has mused that Git records history according to |
| 211 | the victors, whereas Fossil records history as it actually happened. |
| 212 | |
| 213 | <h3>3.8 GPL vs. BSD</h3> |
| 214 | |
| 215 | Git is covered by the GPL license whereas Fossil is covered by |
| 216 | a two-clause BSD license. |
| 217 | |
| 218 | Consider the difference between GPL and BSD licenses: GPL is designed |
| 219 | to make writing easier at the expense of making reading harder. BSD is |
| 220 | designed to make reading easier and the expense of making writing harder. |
| 221 | |
| 222 | To a first approximation, the GPL license grants the right to read |
| 223 | source code to anyone who promises to give back enhancements. In other |
| 224 | words, the act of reading GPL source code (a prerequiste for making changes) |
| 225 | implies acceptance of the license which requires updates to be contributed |
| 226 | back under the same license. (The details are more complex, but the |
| 227 | foregoing captures the essence of the idea.) A big advantage of the GPL |
| @@ -249,11 +249,11 @@ | |
| 249 | <h2>4.0 Missing Features</h2> |
| 250 | |
| 251 | Most of the capabilities found in Git are also available in Fossil and |
| 252 | the other way around. For example, both systems have local check-outs, |
| 253 | remote repositories, push/pull/sync, bisect capabilities, and a "stash". |
| 254 | Both systems store project history as a directed acyclic graph (DAG) |
| 255 | of immutable check-in objects. |
| 256 | |
| 257 | But there are a few capabilities in one system that are missing from the |
| 258 | other. |
| 259 | |
| @@ -271,16 +271,16 @@ | |
| 271 | Git only provides versioning of source code. Fossil strives to provide |
| 272 | other related configuration management services as well. |
| 273 | |
| 274 | * <b>Named branches</b> |
| 275 | |
| 276 | Branches in Fossil have persistent names that are propagated |
| 277 | to collaborators via [/help?cmd=push|push] and [/help?cmd=pull|pull]. |
| 278 | All developers see the same name on the same branch. Git, in contrast, |
| 279 | uses only local branch names, so developers working on the |
| 280 | same project can (and frequently do) use a different name for the |
| 281 | same branch. |
| 282 | |
| 283 | * <b>The [/help?cmd=all|fossil all] command</b> |
| 284 | |
| 285 | Fossil keeps track of all repositories and check-outs and allows |
| 286 | operations over all of them with a single command. For example, in |
| 287 |
+1
-1
| --- www/index.wiki | ||
| +++ www/index.wiki | ||
| @@ -18,11 +18,11 @@ | ||
| 18 | 18 | <ul> |
| 19 | 19 | <li> [http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/fossil-users | sign-up] |
| 20 | 20 | <li> [http://www.mail-archive.com/[email protected] | archives] |
| 21 | 21 | </ul> |
| 22 | 22 | </ul> |
| 23 | -<center><img src="fossil3.gif"></center> | |
| 23 | +<img src="fossil3.gif" align="center"> | |
| 24 | 24 | </div> |
| 25 | 25 | |
| 26 | 26 | <p>Fossil is a simple, high-reliability, distributed software configuration |
| 27 | 27 | management system with these advanced features: |
| 28 | 28 | |
| 29 | 29 |
| --- www/index.wiki | |
| +++ www/index.wiki | |
| @@ -18,11 +18,11 @@ | |
| 18 | <ul> |
| 19 | <li> [http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/fossil-users | sign-up] |
| 20 | <li> [http://www.mail-archive.com/[email protected] | archives] |
| 21 | </ul> |
| 22 | </ul> |
| 23 | <center><img src="fossil3.gif"></center> |
| 24 | </div> |
| 25 | |
| 26 | <p>Fossil is a simple, high-reliability, distributed software configuration |
| 27 | management system with these advanced features: |
| 28 | |
| 29 |
| --- www/index.wiki | |
| +++ www/index.wiki | |
| @@ -18,11 +18,11 @@ | |
| 18 | <ul> |
| 19 | <li> [http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/fossil-users | sign-up] |
| 20 | <li> [http://www.mail-archive.com/[email protected] | archives] |
| 21 | </ul> |
| 22 | </ul> |
| 23 | <img src="fossil3.gif" align="center"> |
| 24 | </div> |
| 25 | |
| 26 | <p>Fossil is a simple, high-reliability, distributed software configuration |
| 27 | management system with these advanced features: |
| 28 | |
| 29 |
+9
-9
| --- www/sync.wiki | ||
| +++ www/sync.wiki | ||
| @@ -15,11 +15,11 @@ | ||
| 15 | 15 | Synchronization is simply the process of sharing artifacts between |
| 16 | 16 | servers so that all servers have copies of all artifacts. Because |
| 17 | 17 | artifacts are unordered, the order in which artifacts are received |
| 18 | 18 | at a server is inconsequential. It is assumed that the SHA1 hashes |
| 19 | 19 | of artifacts are unique - that every artifact has a different SHA1 hash. |
| 20 | -To a first approximation, synchronization proceeds by sharing lists | |
| 20 | +To a first approximation, synchronization proceeds by sharing lists | |
| 21 | 21 | SHA1 hashes of available artifacts, then sharing those artifacts that |
| 22 | 22 | are not found on one side or the other of the connection. In practice, |
| 23 | 23 | a repository might contain millions of artifacts. The list of |
| 24 | 24 | SHA1 hashes for this many artifacts can be large. So optimizations are |
| 25 | 25 | employed that usually reduce the number of SHA1 hashes that need to be |
| @@ -150,11 +150,11 @@ | ||
| 150 | 150 | terminates the login card. The signature is the SHA1 hash of |
| 151 | 151 | the concatenation of the nonce and the users password.</p> |
| 152 | 152 | |
| 153 | 153 | <p>For each login card, the server looks up the user and verifies |
| 154 | 154 | that the nonce matches the SHA1 hash of the remainder of the |
| 155 | -message. It then checks the signature hash to make sure the | |
| 155 | +message. It then checks the signature hash to make sure the | |
| 156 | 156 | signature matches. If everything |
| 157 | 157 | checks out, then the client is granted all privileges of the |
| 158 | 158 | specified user.</p> |
| 159 | 159 | |
| 160 | 160 | <p>Privileges are cumulative. There can be multiple successful |
| @@ -162,11 +162,11 @@ | ||
| 162 | 162 | privileges of each individual login.</p> |
| 163 | 163 | |
| 164 | 164 | <h3>3.3 File and Compressed File Cards</h3> |
| 165 | 165 | |
| 166 | 166 | <p>Artifacts are transferred using either "file" cards, or "cfile" cards. |
| 167 | -(The name "file" card comes from the fact that most artifacts correspond to | |
| 167 | +(The name "file" card comes from the fact that most artifacts correspond to | |
| 168 | 168 | files, and "cfile" is just a compressed file.) |
| 169 | 169 | </p> |
| 170 | 170 | |
| 171 | 171 | <h4>3.3.1 File Cards</h4> |
| 172 | 172 | |
| @@ -230,11 +230,11 @@ | ||
| 230 | 230 | artifact. If the cfile card has four arguments, then the payload is a |
| 231 | 231 | delta and the second argument is the ID of another artifact that is the |
| 232 | 232 | source of the delta and the third argument is the original size of the |
| 233 | 233 | delta artifact.</p> |
| 234 | 234 | |
| 235 | -<p>Unlike file cards, cfile cards are only sent in one direction during a | |
| 235 | +<p>Unlike file cards, cfile cards are only sent in one direction during a | |
| 236 | 236 | clone from server to client for clone protocol version "3" or greater.</p> |
| 237 | 237 | |
| 238 | 238 | <h3>3.4 Push and Pull Cards</h3> |
| 239 | 239 | |
| 240 | 240 | <p>Among the first cards in a client-to-server message are |
| @@ -385,11 +385,11 @@ | ||
| 385 | 385 | </blockquote> |
| 386 | 386 | |
| 387 | 387 | <p>As of [/timeline?r=trunk&c=2015-03-19+03%3A57%3A46&n=20|2015-03-19], the configuration-name must be one of the |
| 388 | 388 | following values: |
| 389 | 389 | |
| 390 | -<center><table border=0> | |
| 390 | +<table border=0 align="center"> | |
| 391 | 391 | <tr><td valign="top"> |
| 392 | 392 | <ul> |
| 393 | 393 | <li> css |
| 394 | 394 | <li> header |
| 395 | 395 | <li> footer |
| @@ -436,11 +436,11 @@ | ||
| 436 | 436 | <li> @reportfmt |
| 437 | 437 | <li> @user |
| 438 | 438 | <li> @concealed |
| 439 | 439 | <li> @shun |
| 440 | 440 | </ul></td></tr> |
| 441 | -</table></center> | |
| 441 | +</table> | |
| 442 | 442 | |
| 443 | 443 | <p>New configuration-names are likely to be added in future releases of |
| 444 | 444 | Fossil. If the server receives a configuration-name that it does not |
| 445 | 445 | understand, the entire reqconfig card is silently ignored. The reqconfig |
| 446 | 446 | card might also be ignored if the user lacks sufficient privilege to |
| @@ -453,11 +453,11 @@ | ||
| 453 | 453 | The value of the configuration item is returned to the client using a |
| 454 | 454 | "config" card. |
| 455 | 455 | |
| 456 | 456 | <p>If the configuration-name begins with "@", that refers to a class of |
| 457 | 457 | values instead of a single value. The content of these configuration items |
| 458 | -is returned in a "config" card that contains pure SQL text that is | |
| 458 | +is returned in a "config" card that contains pure SQL text that is | |
| 459 | 459 | intended to be evaluated by the client. |
| 460 | 460 | |
| 461 | 461 | <p>The @user and @concealed configuration items contain sensitive information |
| 462 | 462 | and are ignored for clients without sufficient privilege. |
| 463 | 463 | |
| @@ -491,11 +491,11 @@ | ||
| 491 | 491 | </blockquote> |
| 492 | 492 | |
| 493 | 493 | <p>The error message is English text that is encoded in order to |
| 494 | 494 | be a single token. |
| 495 | 495 | A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A |
| 496 | -newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash | |
| 496 | +newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash | |
| 497 | 497 | (ASCII 0x5C) is represented as two backslashes "\\". Apart from |
| 498 | 498 | space and newline, no other whitespace characters nor any |
| 499 | 499 | unprintable characters are allowed in |
| 500 | 500 | the error message.</p> |
| 501 | 501 | |
| @@ -658,11 +658,11 @@ | ||
| 658 | 658 | <ol> |
| 659 | 659 | <li>The client sends one or more PUSH HTTP requests to the server. |
| 660 | 660 | The request and reply content type is "application/x-fossil". |
| 661 | 661 | <li>HTTP request content is compressed using zlib. |
| 662 | 662 | <li>The content of request and reply consists of cards with one |
| 663 | - card per line. | |
| 663 | + card per line. | |
| 664 | 664 | <li>Card formats are: |
| 665 | 665 | <ul> |
| 666 | 666 | <li> <b>login</b> <i>userid nonce signature</i> |
| 667 | 667 | <li> <b>push</b> <i>servercode projectcode</i> |
| 668 | 668 | <li> <b>pull</b> <i>servercode projectcode</i> |
| 669 | 669 |
| --- www/sync.wiki | |
| +++ www/sync.wiki | |
| @@ -15,11 +15,11 @@ | |
| 15 | Synchronization is simply the process of sharing artifacts between |
| 16 | servers so that all servers have copies of all artifacts. Because |
| 17 | artifacts are unordered, the order in which artifacts are received |
| 18 | at a server is inconsequential. It is assumed that the SHA1 hashes |
| 19 | of artifacts are unique - that every artifact has a different SHA1 hash. |
| 20 | To a first approximation, synchronization proceeds by sharing lists |
| 21 | SHA1 hashes of available artifacts, then sharing those artifacts that |
| 22 | are not found on one side or the other of the connection. In practice, |
| 23 | a repository might contain millions of artifacts. The list of |
| 24 | SHA1 hashes for this many artifacts can be large. So optimizations are |
| 25 | employed that usually reduce the number of SHA1 hashes that need to be |
| @@ -150,11 +150,11 @@ | |
| 150 | terminates the login card. The signature is the SHA1 hash of |
| 151 | the concatenation of the nonce and the users password.</p> |
| 152 | |
| 153 | <p>For each login card, the server looks up the user and verifies |
| 154 | that the nonce matches the SHA1 hash of the remainder of the |
| 155 | message. It then checks the signature hash to make sure the |
| 156 | signature matches. If everything |
| 157 | checks out, then the client is granted all privileges of the |
| 158 | specified user.</p> |
| 159 | |
| 160 | <p>Privileges are cumulative. There can be multiple successful |
| @@ -162,11 +162,11 @@ | |
| 162 | privileges of each individual login.</p> |
| 163 | |
| 164 | <h3>3.3 File and Compressed File Cards</h3> |
| 165 | |
| 166 | <p>Artifacts are transferred using either "file" cards, or "cfile" cards. |
| 167 | (The name "file" card comes from the fact that most artifacts correspond to |
| 168 | files, and "cfile" is just a compressed file.) |
| 169 | </p> |
| 170 | |
| 171 | <h4>3.3.1 File Cards</h4> |
| 172 | |
| @@ -230,11 +230,11 @@ | |
| 230 | artifact. If the cfile card has four arguments, then the payload is a |
| 231 | delta and the second argument is the ID of another artifact that is the |
| 232 | source of the delta and the third argument is the original size of the |
| 233 | delta artifact.</p> |
| 234 | |
| 235 | <p>Unlike file cards, cfile cards are only sent in one direction during a |
| 236 | clone from server to client for clone protocol version "3" or greater.</p> |
| 237 | |
| 238 | <h3>3.4 Push and Pull Cards</h3> |
| 239 | |
| 240 | <p>Among the first cards in a client-to-server message are |
| @@ -385,11 +385,11 @@ | |
| 385 | </blockquote> |
| 386 | |
| 387 | <p>As of [/timeline?r=trunk&c=2015-03-19+03%3A57%3A46&n=20|2015-03-19], the configuration-name must be one of the |
| 388 | following values: |
| 389 | |
| 390 | <center><table border=0> |
| 391 | <tr><td valign="top"> |
| 392 | <ul> |
| 393 | <li> css |
| 394 | <li> header |
| 395 | <li> footer |
| @@ -436,11 +436,11 @@ | |
| 436 | <li> @reportfmt |
| 437 | <li> @user |
| 438 | <li> @concealed |
| 439 | <li> @shun |
| 440 | </ul></td></tr> |
| 441 | </table></center> |
| 442 | |
| 443 | <p>New configuration-names are likely to be added in future releases of |
| 444 | Fossil. If the server receives a configuration-name that it does not |
| 445 | understand, the entire reqconfig card is silently ignored. The reqconfig |
| 446 | card might also be ignored if the user lacks sufficient privilege to |
| @@ -453,11 +453,11 @@ | |
| 453 | The value of the configuration item is returned to the client using a |
| 454 | "config" card. |
| 455 | |
| 456 | <p>If the configuration-name begins with "@", that refers to a class of |
| 457 | values instead of a single value. The content of these configuration items |
| 458 | is returned in a "config" card that contains pure SQL text that is |
| 459 | intended to be evaluated by the client. |
| 460 | |
| 461 | <p>The @user and @concealed configuration items contain sensitive information |
| 462 | and are ignored for clients without sufficient privilege. |
| 463 | |
| @@ -491,11 +491,11 @@ | |
| 491 | </blockquote> |
| 492 | |
| 493 | <p>The error message is English text that is encoded in order to |
| 494 | be a single token. |
| 495 | A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A |
| 496 | newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash |
| 497 | (ASCII 0x5C) is represented as two backslashes "\\". Apart from |
| 498 | space and newline, no other whitespace characters nor any |
| 499 | unprintable characters are allowed in |
| 500 | the error message.</p> |
| 501 | |
| @@ -658,11 +658,11 @@ | |
| 658 | <ol> |
| 659 | <li>The client sends one or more PUSH HTTP requests to the server. |
| 660 | The request and reply content type is "application/x-fossil". |
| 661 | <li>HTTP request content is compressed using zlib. |
| 662 | <li>The content of request and reply consists of cards with one |
| 663 | card per line. |
| 664 | <li>Card formats are: |
| 665 | <ul> |
| 666 | <li> <b>login</b> <i>userid nonce signature</i> |
| 667 | <li> <b>push</b> <i>servercode projectcode</i> |
| 668 | <li> <b>pull</b> <i>servercode projectcode</i> |
| 669 |
| --- www/sync.wiki | |
| +++ www/sync.wiki | |
| @@ -15,11 +15,11 @@ | |
| 15 | Synchronization is simply the process of sharing artifacts between |
| 16 | servers so that all servers have copies of all artifacts. Because |
| 17 | artifacts are unordered, the order in which artifacts are received |
| 18 | at a server is inconsequential. It is assumed that the SHA1 hashes |
| 19 | of artifacts are unique - that every artifact has a different SHA1 hash. |
| 20 | To a first approximation, synchronization proceeds by sharing lists |
| 21 | SHA1 hashes of available artifacts, then sharing those artifacts that |
| 22 | are not found on one side or the other of the connection. In practice, |
| 23 | a repository might contain millions of artifacts. The list of |
| 24 | SHA1 hashes for this many artifacts can be large. So optimizations are |
| 25 | employed that usually reduce the number of SHA1 hashes that need to be |
| @@ -150,11 +150,11 @@ | |
| 150 | terminates the login card. The signature is the SHA1 hash of |
| 151 | the concatenation of the nonce and the users password.</p> |
| 152 | |
| 153 | <p>For each login card, the server looks up the user and verifies |
| 154 | that the nonce matches the SHA1 hash of the remainder of the |
| 155 | message. It then checks the signature hash to make sure the |
| 156 | signature matches. If everything |
| 157 | checks out, then the client is granted all privileges of the |
| 158 | specified user.</p> |
| 159 | |
| 160 | <p>Privileges are cumulative. There can be multiple successful |
| @@ -162,11 +162,11 @@ | |
| 162 | privileges of each individual login.</p> |
| 163 | |
| 164 | <h3>3.3 File and Compressed File Cards</h3> |
| 165 | |
| 166 | <p>Artifacts are transferred using either "file" cards, or "cfile" cards. |
| 167 | (The name "file" card comes from the fact that most artifacts correspond to |
| 168 | files, and "cfile" is just a compressed file.) |
| 169 | </p> |
| 170 | |
| 171 | <h4>3.3.1 File Cards</h4> |
| 172 | |
| @@ -230,11 +230,11 @@ | |
| 230 | artifact. If the cfile card has four arguments, then the payload is a |
| 231 | delta and the second argument is the ID of another artifact that is the |
| 232 | source of the delta and the third argument is the original size of the |
| 233 | delta artifact.</p> |
| 234 | |
| 235 | <p>Unlike file cards, cfile cards are only sent in one direction during a |
| 236 | clone from server to client for clone protocol version "3" or greater.</p> |
| 237 | |
| 238 | <h3>3.4 Push and Pull Cards</h3> |
| 239 | |
| 240 | <p>Among the first cards in a client-to-server message are |
| @@ -385,11 +385,11 @@ | |
| 385 | </blockquote> |
| 386 | |
| 387 | <p>As of [/timeline?r=trunk&c=2015-03-19+03%3A57%3A46&n=20|2015-03-19], the configuration-name must be one of the |
| 388 | following values: |
| 389 | |
| 390 | <table border=0 align="center"> |
| 391 | <tr><td valign="top"> |
| 392 | <ul> |
| 393 | <li> css |
| 394 | <li> header |
| 395 | <li> footer |
| @@ -436,11 +436,11 @@ | |
| 436 | <li> @reportfmt |
| 437 | <li> @user |
| 438 | <li> @concealed |
| 439 | <li> @shun |
| 440 | </ul></td></tr> |
| 441 | </table> |
| 442 | |
| 443 | <p>New configuration-names are likely to be added in future releases of |
| 444 | Fossil. If the server receives a configuration-name that it does not |
| 445 | understand, the entire reqconfig card is silently ignored. The reqconfig |
| 446 | card might also be ignored if the user lacks sufficient privilege to |
| @@ -453,11 +453,11 @@ | |
| 453 | The value of the configuration item is returned to the client using a |
| 454 | "config" card. |
| 455 | |
| 456 | <p>If the configuration-name begins with "@", that refers to a class of |
| 457 | values instead of a single value. The content of these configuration items |
| 458 | is returned in a "config" card that contains pure SQL text that is |
| 459 | intended to be evaluated by the client. |
| 460 | |
| 461 | <p>The @user and @concealed configuration items contain sensitive information |
| 462 | and are ignored for clients without sufficient privilege. |
| 463 | |
| @@ -491,11 +491,11 @@ | |
| 491 | </blockquote> |
| 492 | |
| 493 | <p>The error message is English text that is encoded in order to |
| 494 | be a single token. |
| 495 | A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A |
| 496 | newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash |
| 497 | (ASCII 0x5C) is represented as two backslashes "\\". Apart from |
| 498 | space and newline, no other whitespace characters nor any |
| 499 | unprintable characters are allowed in |
| 500 | the error message.</p> |
| 501 | |
| @@ -658,11 +658,11 @@ | |
| 658 | <ol> |
| 659 | <li>The client sends one or more PUSH HTTP requests to the server. |
| 660 | The request and reply content type is "application/x-fossil". |
| 661 | <li>HTTP request content is compressed using zlib. |
| 662 | <li>The content of request and reply consists of cards with one |
| 663 | card per line. |
| 664 | <li>Card formats are: |
| 665 | <ul> |
| 666 | <li> <b>login</b> <i>userid nonce signature</i> |
| 667 | <li> <b>push</b> <i>servercode projectcode</i> |
| 668 | <li> <b>pull</b> <i>servercode projectcode</i> |
| 669 |
+18
-19
| --- www/tech_overview.wiki | ||
| +++ www/tech_overview.wiki | ||
| @@ -5,12 +5,12 @@ | ||
| 5 | 5 | |
| 6 | 6 | <h2>1.0 Introduction</h2> |
| 7 | 7 | |
| 8 | 8 | At its lowest level, a Fossil repository consists of an unordered set |
| 9 | 9 | of immutable "artifacts". You might think of these artifacts as "files", |
| 10 | -since in many cases the artifacts are exactly that. | |
| 11 | -But other "control artifacts" | |
| 10 | +since in many cases the artifacts are exactly that. | |
| 11 | +But other "control artifacts" | |
| 12 | 12 | are also included in the mix. These control artifacts define the relationships |
| 13 | 13 | between artifacts - which files go together to form a particular |
| 14 | 14 | version of the project, who checked in that version and when, what was |
| 15 | 15 | the check-in comment, what wiki pages are included with the project, what |
| 16 | 16 | are the edit histories of each wiki page, what bug reports or tickets are |
| @@ -17,21 +17,21 @@ | ||
| 17 | 17 | included, who contributed to the evolution of each ticket, and so forth. |
| 18 | 18 | This low-level file format is called the "global state" of |
| 19 | 19 | the repository, since this is the information that is synced to peer |
| 20 | 20 | repositories using push and pull operations. The low-level file format |
| 21 | 21 | is also called "enduring" since it is intended to last for many years. |
| 22 | -The details of the low-level, enduring, global file format | |
| 22 | +The details of the low-level, enduring, global file format | |
| 23 | 23 | are [./fileformat.wiki | described separately]. |
| 24 | 24 | |
| 25 | 25 | This article is about how Fossil is currently implemented. Instead of |
| 26 | 26 | dealing with vague abstractions of "enduring file formats" as the |
| 27 | 27 | [./fileformat.wiki | other document] does, this article provides |
| 28 | -some detail on how Fossil actually stores information on disk. | |
| 28 | +some detail on how Fossil actually stores information on disk. | |
| 29 | 29 | |
| 30 | 30 | <h2>2.0 Three Databases</h2> |
| 31 | 31 | |
| 32 | -Fossil stores state information in | |
| 32 | +Fossil stores state information in | |
| 33 | 33 | [http://www.sqlite.org/ | SQLite] database files. |
| 34 | 34 | SQLite keeps an entire relational database, including multiple tables and |
| 35 | 35 | indices, in a single disk file. The SQLite library allows the database |
| 36 | 36 | files to be efficiently queried and updated using the industry-standard |
| 37 | 37 | SQL language. SQLite updates are atomic, so even in the event of |
| @@ -46,11 +46,11 @@ | ||
| 46 | 46 | </ol> |
| 47 | 47 | |
| 48 | 48 | The configuration database is a one-per-user database that holds |
| 49 | 49 | global configuration information used by Fossil. There is one |
| 50 | 50 | repository database per project. The repository database is the |
| 51 | -file that people are normally referring to when they say | |
| 51 | +file that people are normally referring to when they say | |
| 52 | 52 | "a Fossil repository". The checkout database is found in the working |
| 53 | 53 | checkout for a project and contains state information that is unique |
| 54 | 54 | to that working checkout. |
| 55 | 55 | |
| 56 | 56 | Fossil does not always use all three database files. The web interface, |
| @@ -65,11 +65,11 @@ | ||
| 65 | 65 | SQLite's [http://www.sqlite.org/lang_attach.html | ATTACH] command. |
| 66 | 66 | |
| 67 | 67 | The chart below provides a quick summary of how each of these |
| 68 | 68 | database files are used by Fossil, with detailed discussion following. |
| 69 | 69 | |
| 70 | -<center><table border="1" width="80%" cellpadding="0"> | |
| 70 | +<table border="1" width="80%" cellpadding="0" align="center"> | |
| 71 | 71 | <tr> |
| 72 | 72 | <td width="33%" valign="top"> |
| 73 | 73 | <h3 align="center">Configuration Database<br>"~/.fossil"</h3> |
| 74 | 74 | <ul> |
| 75 | 75 | <li>Global [/help/setting |settings] |
| @@ -103,11 +103,10 @@ | ||
| 103 | 103 | <li>Information needed to "[/help/undo|undo]" or "[/help/redo|redo]" |
| 104 | 104 | </ul> |
| 105 | 105 | </td> |
| 106 | 106 | </tr> |
| 107 | 107 | </table> |
| 108 | -</center> | |
| 109 | 108 | |
| 110 | 109 | <h3>2.1 The Configuration Database</h3> |
| 111 | 110 | |
| 112 | 111 | The configuration database holds cross-repository preferences and a list of all |
| 113 | 112 | repositories for a single user. |
| @@ -135,11 +134,11 @@ | ||
| 135 | 134 | You can override this default location by defining the environment |
| 136 | 135 | variable FOSSIL_HOME pointing to an appropriate (writable) directory. |
| 137 | 136 | |
| 138 | 137 | <h3>2.2 Repository Databases</h3> |
| 139 | 138 | |
| 140 | -The repository database is the file that is commonly referred to as | |
| 139 | +The repository database is the file that is commonly referred to as | |
| 141 | 140 | "the repository". This is because the repository database contains, |
| 142 | 141 | among other things, the complete revision, ticket, and wiki history for |
| 143 | 142 | a project. It is customary to name the repository database after then |
| 144 | 143 | name of the project, with a ".fossil" suffix. For example, the repository |
| 145 | 144 | database for the self-hosting Fossil repository is called "fossil.fossil" |
| @@ -146,11 +145,11 @@ | ||
| 146 | 145 | and the repository database for SQLite is called "sqlite.fossil". |
| 147 | 146 | |
| 148 | 147 | <h4>2.2.1 Global Project State</h4> |
| 149 | 148 | |
| 150 | 149 | The bulk of the repository database (typically 75 to 85%) consists |
| 151 | -of the artifacts that comprise the | |
| 150 | +of the artifacts that comprise the | |
| 152 | 151 | [./fileformat.wiki | enduring, global, shared state] of the project. |
| 153 | 152 | The artifacts are stored as BLOBs, compressed using |
| 154 | 153 | [http://www.zlib.net/ | zlib compression] and, where applicable, |
| 155 | 154 | using [./delta_encoder_algorithm.wiki | delta compression]. |
| 156 | 155 | The combination of zlib and delta compression results in a considerable |
| @@ -160,26 +159,26 @@ | ||
| 160 | 159 | 32 MB of space in the repository database, for a compression ratio |
| 161 | 160 | of about 64:1. The average size of a content BLOB in the database |
| 162 | 161 | is around 500 bytes. |
| 163 | 162 | |
| 164 | 163 | Note that the zlib and delta compression is not an inherent part of the |
| 165 | -Fossil file format; it is just an optimization. | |
| 164 | +Fossil file format; it is just an optimization. | |
| 166 | 165 | The enduring file format for Fossil is the unordered |
| 167 | 166 | set of artifacts. The compression techniques are just a detail of |
| 168 | 167 | how the current implementation of Fossil happens to store these artifacts |
| 169 | 168 | efficiently on disk. |
| 170 | 169 | |
| 171 | 170 | All of the original uncompressed and undeltaed artifacts can be extracted |
| 172 | -from a Fossil repository database using | |
| 171 | +from a Fossil repository database using | |
| 173 | 172 | the [/help/deconstruct | fossil deconstruct] |
| 174 | 173 | command. Individual artifacts can be extracted using the |
| 175 | 174 | [/help/artifact | fossil artifact] command. |
| 176 | 175 | When accessing the repository database using raw SQL and the |
| 177 | 176 | [/help/sqlite3 | fossil sql] command, the extension function |
| 178 | 177 | "<tt>content()</tt>" with a single argument which is the SHA1 hash |
| 179 | 178 | of an artifact will return the complete undeleted and uncompressed |
| 180 | -content of that artifact. | |
| 179 | +content of that artifact. | |
| 181 | 180 | |
| 182 | 181 | Going the other way, the [/help/reconstruct | fossil reconstruct] |
| 183 | 182 | command will scan a directory hierarchy and add all files found to |
| 184 | 183 | a new repository database. The [/help/import | fossil import] command |
| 185 | 184 | works by reading the input git-fast-export stream and using it to construct |
| @@ -225,11 +224,11 @@ | ||
| 225 | 224 | by [/help/sync | fossil sync]. That is because it is entirely reasonable |
| 226 | 225 | that two different websites for the same project might have completely |
| 227 | 226 | different display preferences and user communities. One instance of the |
| 228 | 227 | project might be a fork of the other, for example, which pulls from the |
| 229 | 228 | other but never pushes and extends the project in ways that the keepers of |
| 230 | -the other website disapprove of. | |
| 229 | +the other website disapprove of. | |
| 231 | 230 | |
| 232 | 231 | Display and processing information includes the following: |
| 233 | 232 | |
| 234 | 233 | * The name and description of the project |
| 235 | 234 | * The CSS file, header, and footer used by all web pages |
| @@ -242,31 +241,31 @@ | ||
| 242 | 241 | global values defined in the per-user configuration database. |
| 243 | 242 | |
| 244 | 243 | Though the display and processing preferences do not move between |
| 245 | 244 | repository instances using [/help/sync | fossil sync], this information |
| 246 | 245 | can be shared between repositories using the |
| 247 | -[/help/config | fossil config push] and | |
| 246 | +[/help/config | fossil config push] and | |
| 248 | 247 | [/help/config | fossil config pull] commands. |
| 249 | 248 | The display and processing information is also copied into new |
| 250 | 249 | repositories when they are created using |
| 251 | 250 | [/help/clone | fossil clone]. |
| 252 | 251 | |
| 253 | 252 | <h4>2.2.4 User Credentials And Privileges</h4> |
| 254 | 253 | |
| 255 | 254 | Just because two development teams are collaborating on a project and allow |
| 256 | -push and/or pull between their repositories does not mean that they | |
| 255 | +push and/or pull between their repositories does not mean that they | |
| 257 | 256 | trust each other enough to share passwords and access privileges. |
| 258 | 257 | Hence the names and emails and passwords and privileges of users are |
| 259 | 258 | considered private information that is kept locally in each repository. |
| 260 | 259 | |
| 261 | 260 | Each repository database has a table holding the username, privileges, |
| 262 | 261 | and login credentials for users authorized to interact with that particular |
| 263 | -database. In addition, there is a table named "concealed" that maps the | |
| 262 | +database. In addition, there is a table named "concealed" that maps the | |
| 264 | 263 | SHA1 hash of each users email address back into their true email address. |
| 265 | 264 | The concealed table allows just the SHA1 hash of email addresses to |
| 266 | 265 | be stored in tickets, and thus prevents actual email addresses from falling |
| 267 | -into the hands of spammers who happen to clone the repository. | |
| 266 | +into the hands of spammers who happen to clone the repository. | |
| 268 | 267 | |
| 269 | 268 | The content of the user and concealed tables can be pushed and pulled using the |
| 270 | 269 | [/help/config | fossil config push] and |
| 271 | 270 | [/help/config | fossil config pull] commands with the "user" and |
| 272 | 271 | "email" as the AREA argument, but only if you have administrative |
| @@ -278,11 +277,11 @@ | ||
| 278 | 277 | project - is intended to be an append-only database. In other words, |
| 279 | 278 | new artifacts can be added but artifacts can never be removed. But |
| 280 | 279 | it sometimes happens that inappropriate content is mistakenly or |
| 281 | 280 | maliciously added to a repository. The only way to get rid of |
| 282 | 281 | the undesired content is to [./shunning.wiki | "shun"] it. |
| 283 | -The "shun" table in the repository database records the SHA1 hash of | |
| 282 | +The "shun" table in the repository database records the SHA1 hash of | |
| 284 | 283 | all shunned artifacts. |
| 285 | 284 | |
| 286 | 285 | The shun table can be pushed or pulled using |
| 287 | 286 | the [/help/config | fossil config] command with the "shun" AREA argument. |
| 288 | 287 | The shun table is also copied during a [/help/clone | clone]. |
| 289 | 288 |
| --- www/tech_overview.wiki | |
| +++ www/tech_overview.wiki | |
| @@ -5,12 +5,12 @@ | |
| 5 | |
| 6 | <h2>1.0 Introduction</h2> |
| 7 | |
| 8 | At its lowest level, a Fossil repository consists of an unordered set |
| 9 | of immutable "artifacts". You might think of these artifacts as "files", |
| 10 | since in many cases the artifacts are exactly that. |
| 11 | But other "control artifacts" |
| 12 | are also included in the mix. These control artifacts define the relationships |
| 13 | between artifacts - which files go together to form a particular |
| 14 | version of the project, who checked in that version and when, what was |
| 15 | the check-in comment, what wiki pages are included with the project, what |
| 16 | are the edit histories of each wiki page, what bug reports or tickets are |
| @@ -17,21 +17,21 @@ | |
| 17 | included, who contributed to the evolution of each ticket, and so forth. |
| 18 | This low-level file format is called the "global state" of |
| 19 | the repository, since this is the information that is synced to peer |
| 20 | repositories using push and pull operations. The low-level file format |
| 21 | is also called "enduring" since it is intended to last for many years. |
| 22 | The details of the low-level, enduring, global file format |
| 23 | are [./fileformat.wiki | described separately]. |
| 24 | |
| 25 | This article is about how Fossil is currently implemented. Instead of |
| 26 | dealing with vague abstractions of "enduring file formats" as the |
| 27 | [./fileformat.wiki | other document] does, this article provides |
| 28 | some detail on how Fossil actually stores information on disk. |
| 29 | |
| 30 | <h2>2.0 Three Databases</h2> |
| 31 | |
| 32 | Fossil stores state information in |
| 33 | [http://www.sqlite.org/ | SQLite] database files. |
| 34 | SQLite keeps an entire relational database, including multiple tables and |
| 35 | indices, in a single disk file. The SQLite library allows the database |
| 36 | files to be efficiently queried and updated using the industry-standard |
| 37 | SQL language. SQLite updates are atomic, so even in the event of |
| @@ -46,11 +46,11 @@ | |
| 46 | </ol> |
| 47 | |
| 48 | The configuration database is a one-per-user database that holds |
| 49 | global configuration information used by Fossil. There is one |
| 50 | repository database per project. The repository database is the |
| 51 | file that people are normally referring to when they say |
| 52 | "a Fossil repository". The checkout database is found in the working |
| 53 | checkout for a project and contains state information that is unique |
| 54 | to that working checkout. |
| 55 | |
| 56 | Fossil does not always use all three database files. The web interface, |
| @@ -65,11 +65,11 @@ | |
| 65 | SQLite's [http://www.sqlite.org/lang_attach.html | ATTACH] command. |
| 66 | |
| 67 | The chart below provides a quick summary of how each of these |
| 68 | database files are used by Fossil, with detailed discussion following. |
| 69 | |
| 70 | <center><table border="1" width="80%" cellpadding="0"> |
| 71 | <tr> |
| 72 | <td width="33%" valign="top"> |
| 73 | <h3 align="center">Configuration Database<br>"~/.fossil"</h3> |
| 74 | <ul> |
| 75 | <li>Global [/help/setting |settings] |
| @@ -103,11 +103,10 @@ | |
| 103 | <li>Information needed to "[/help/undo|undo]" or "[/help/redo|redo]" |
| 104 | </ul> |
| 105 | </td> |
| 106 | </tr> |
| 107 | </table> |
| 108 | </center> |
| 109 | |
| 110 | <h3>2.1 The Configuration Database</h3> |
| 111 | |
| 112 | The configuration database holds cross-repository preferences and a list of all |
| 113 | repositories for a single user. |
| @@ -135,11 +134,11 @@ | |
| 135 | You can override this default location by defining the environment |
| 136 | variable FOSSIL_HOME pointing to an appropriate (writable) directory. |
| 137 | |
| 138 | <h3>2.2 Repository Databases</h3> |
| 139 | |
| 140 | The repository database is the file that is commonly referred to as |
| 141 | "the repository". This is because the repository database contains, |
| 142 | among other things, the complete revision, ticket, and wiki history for |
| 143 | a project. It is customary to name the repository database after then |
| 144 | name of the project, with a ".fossil" suffix. For example, the repository |
| 145 | database for the self-hosting Fossil repository is called "fossil.fossil" |
| @@ -146,11 +145,11 @@ | |
| 146 | and the repository database for SQLite is called "sqlite.fossil". |
| 147 | |
| 148 | <h4>2.2.1 Global Project State</h4> |
| 149 | |
| 150 | The bulk of the repository database (typically 75 to 85%) consists |
| 151 | of the artifacts that comprise the |
| 152 | [./fileformat.wiki | enduring, global, shared state] of the project. |
| 153 | The artifacts are stored as BLOBs, compressed using |
| 154 | [http://www.zlib.net/ | zlib compression] and, where applicable, |
| 155 | using [./delta_encoder_algorithm.wiki | delta compression]. |
| 156 | The combination of zlib and delta compression results in a considerable |
| @@ -160,26 +159,26 @@ | |
| 160 | 32 MB of space in the repository database, for a compression ratio |
| 161 | of about 64:1. The average size of a content BLOB in the database |
| 162 | is around 500 bytes. |
| 163 | |
| 164 | Note that the zlib and delta compression is not an inherent part of the |
| 165 | Fossil file format; it is just an optimization. |
| 166 | The enduring file format for Fossil is the unordered |
| 167 | set of artifacts. The compression techniques are just a detail of |
| 168 | how the current implementation of Fossil happens to store these artifacts |
| 169 | efficiently on disk. |
| 170 | |
| 171 | All of the original uncompressed and undeltaed artifacts can be extracted |
| 172 | from a Fossil repository database using |
| 173 | the [/help/deconstruct | fossil deconstruct] |
| 174 | command. Individual artifacts can be extracted using the |
| 175 | [/help/artifact | fossil artifact] command. |
| 176 | When accessing the repository database using raw SQL and the |
| 177 | [/help/sqlite3 | fossil sql] command, the extension function |
| 178 | "<tt>content()</tt>" with a single argument which is the SHA1 hash |
| 179 | of an artifact will return the complete undeleted and uncompressed |
| 180 | content of that artifact. |
| 181 | |
| 182 | Going the other way, the [/help/reconstruct | fossil reconstruct] |
| 183 | command will scan a directory hierarchy and add all files found to |
| 184 | a new repository database. The [/help/import | fossil import] command |
| 185 | works by reading the input git-fast-export stream and using it to construct |
| @@ -225,11 +224,11 @@ | |
| 225 | by [/help/sync | fossil sync]. That is because it is entirely reasonable |
| 226 | that two different websites for the same project might have completely |
| 227 | different display preferences and user communities. One instance of the |
| 228 | project might be a fork of the other, for example, which pulls from the |
| 229 | other but never pushes and extends the project in ways that the keepers of |
| 230 | the other website disapprove of. |
| 231 | |
| 232 | Display and processing information includes the following: |
| 233 | |
| 234 | * The name and description of the project |
| 235 | * The CSS file, header, and footer used by all web pages |
| @@ -242,31 +241,31 @@ | |
| 242 | global values defined in the per-user configuration database. |
| 243 | |
| 244 | Though the display and processing preferences do not move between |
| 245 | repository instances using [/help/sync | fossil sync], this information |
| 246 | can be shared between repositories using the |
| 247 | [/help/config | fossil config push] and |
| 248 | [/help/config | fossil config pull] commands. |
| 249 | The display and processing information is also copied into new |
| 250 | repositories when they are created using |
| 251 | [/help/clone | fossil clone]. |
| 252 | |
| 253 | <h4>2.2.4 User Credentials And Privileges</h4> |
| 254 | |
| 255 | Just because two development teams are collaborating on a project and allow |
| 256 | push and/or pull between their repositories does not mean that they |
| 257 | trust each other enough to share passwords and access privileges. |
| 258 | Hence the names and emails and passwords and privileges of users are |
| 259 | considered private information that is kept locally in each repository. |
| 260 | |
| 261 | Each repository database has a table holding the username, privileges, |
| 262 | and login credentials for users authorized to interact with that particular |
| 263 | database. In addition, there is a table named "concealed" that maps the |
| 264 | SHA1 hash of each users email address back into their true email address. |
| 265 | The concealed table allows just the SHA1 hash of email addresses to |
| 266 | be stored in tickets, and thus prevents actual email addresses from falling |
| 267 | into the hands of spammers who happen to clone the repository. |
| 268 | |
| 269 | The content of the user and concealed tables can be pushed and pulled using the |
| 270 | [/help/config | fossil config push] and |
| 271 | [/help/config | fossil config pull] commands with the "user" and |
| 272 | "email" as the AREA argument, but only if you have administrative |
| @@ -278,11 +277,11 @@ | |
| 278 | project - is intended to be an append-only database. In other words, |
| 279 | new artifacts can be added but artifacts can never be removed. But |
| 280 | it sometimes happens that inappropriate content is mistakenly or |
| 281 | maliciously added to a repository. The only way to get rid of |
| 282 | the undesired content is to [./shunning.wiki | "shun"] it. |
| 283 | The "shun" table in the repository database records the SHA1 hash of |
| 284 | all shunned artifacts. |
| 285 | |
| 286 | The shun table can be pushed or pulled using |
| 287 | the [/help/config | fossil config] command with the "shun" AREA argument. |
| 288 | The shun table is also copied during a [/help/clone | clone]. |
| 289 |
| --- www/tech_overview.wiki | |
| +++ www/tech_overview.wiki | |
| @@ -5,12 +5,12 @@ | |
| 5 | |
| 6 | <h2>1.0 Introduction</h2> |
| 7 | |
| 8 | At its lowest level, a Fossil repository consists of an unordered set |
| 9 | of immutable "artifacts". You might think of these artifacts as "files", |
| 10 | since in many cases the artifacts are exactly that. |
| 11 | But other "control artifacts" |
| 12 | are also included in the mix. These control artifacts define the relationships |
| 13 | between artifacts - which files go together to form a particular |
| 14 | version of the project, who checked in that version and when, what was |
| 15 | the check-in comment, what wiki pages are included with the project, what |
| 16 | are the edit histories of each wiki page, what bug reports or tickets are |
| @@ -17,21 +17,21 @@ | |
| 17 | included, who contributed to the evolution of each ticket, and so forth. |
| 18 | This low-level file format is called the "global state" of |
| 19 | the repository, since this is the information that is synced to peer |
| 20 | repositories using push and pull operations. The low-level file format |
| 21 | is also called "enduring" since it is intended to last for many years. |
| 22 | The details of the low-level, enduring, global file format |
| 23 | are [./fileformat.wiki | described separately]. |
| 24 | |
| 25 | This article is about how Fossil is currently implemented. Instead of |
| 26 | dealing with vague abstractions of "enduring file formats" as the |
| 27 | [./fileformat.wiki | other document] does, this article provides |
| 28 | some detail on how Fossil actually stores information on disk. |
| 29 | |
| 30 | <h2>2.0 Three Databases</h2> |
| 31 | |
| 32 | Fossil stores state information in |
| 33 | [http://www.sqlite.org/ | SQLite] database files. |
| 34 | SQLite keeps an entire relational database, including multiple tables and |
| 35 | indices, in a single disk file. The SQLite library allows the database |
| 36 | files to be efficiently queried and updated using the industry-standard |
| 37 | SQL language. SQLite updates are atomic, so even in the event of |
| @@ -46,11 +46,11 @@ | |
| 46 | </ol> |
| 47 | |
| 48 | The configuration database is a one-per-user database that holds |
| 49 | global configuration information used by Fossil. There is one |
| 50 | repository database per project. The repository database is the |
| 51 | file that people are normally referring to when they say |
| 52 | "a Fossil repository". The checkout database is found in the working |
| 53 | checkout for a project and contains state information that is unique |
| 54 | to that working checkout. |
| 55 | |
| 56 | Fossil does not always use all three database files. The web interface, |
| @@ -65,11 +65,11 @@ | |
| 65 | SQLite's [http://www.sqlite.org/lang_attach.html | ATTACH] command. |
| 66 | |
| 67 | The chart below provides a quick summary of how each of these |
| 68 | database files are used by Fossil, with detailed discussion following. |
| 69 | |
| 70 | <table border="1" width="80%" cellpadding="0" align="center"> |
| 71 | <tr> |
| 72 | <td width="33%" valign="top"> |
| 73 | <h3 align="center">Configuration Database<br>"~/.fossil"</h3> |
| 74 | <ul> |
| 75 | <li>Global [/help/setting |settings] |
| @@ -103,11 +103,10 @@ | |
| 103 | <li>Information needed to "[/help/undo|undo]" or "[/help/redo|redo]" |
| 104 | </ul> |
| 105 | </td> |
| 106 | </tr> |
| 107 | </table> |
| 108 | |
| 109 | <h3>2.1 The Configuration Database</h3> |
| 110 | |
| 111 | The configuration database holds cross-repository preferences and a list of all |
| 112 | repositories for a single user. |
| @@ -135,11 +134,11 @@ | |
| 134 | You can override this default location by defining the environment |
| 135 | variable FOSSIL_HOME pointing to an appropriate (writable) directory. |
| 136 | |
| 137 | <h3>2.2 Repository Databases</h3> |
| 138 | |
| 139 | The repository database is the file that is commonly referred to as |
| 140 | "the repository". This is because the repository database contains, |
| 141 | among other things, the complete revision, ticket, and wiki history for |
| 142 | a project. It is customary to name the repository database after then |
| 143 | name of the project, with a ".fossil" suffix. For example, the repository |
| 144 | database for the self-hosting Fossil repository is called "fossil.fossil" |
| @@ -146,11 +145,11 @@ | |
| 145 | and the repository database for SQLite is called "sqlite.fossil". |
| 146 | |
| 147 | <h4>2.2.1 Global Project State</h4> |
| 148 | |
| 149 | The bulk of the repository database (typically 75 to 85%) consists |
| 150 | of the artifacts that comprise the |
| 151 | [./fileformat.wiki | enduring, global, shared state] of the project. |
| 152 | The artifacts are stored as BLOBs, compressed using |
| 153 | [http://www.zlib.net/ | zlib compression] and, where applicable, |
| 154 | using [./delta_encoder_algorithm.wiki | delta compression]. |
| 155 | The combination of zlib and delta compression results in a considerable |
| @@ -160,26 +159,26 @@ | |
| 159 | 32 MB of space in the repository database, for a compression ratio |
| 160 | of about 64:1. The average size of a content BLOB in the database |
| 161 | is around 500 bytes. |
| 162 | |
| 163 | Note that the zlib and delta compression is not an inherent part of the |
| 164 | Fossil file format; it is just an optimization. |
| 165 | The enduring file format for Fossil is the unordered |
| 166 | set of artifacts. The compression techniques are just a detail of |
| 167 | how the current implementation of Fossil happens to store these artifacts |
| 168 | efficiently on disk. |
| 169 | |
| 170 | All of the original uncompressed and undeltaed artifacts can be extracted |
| 171 | from a Fossil repository database using |
| 172 | the [/help/deconstruct | fossil deconstruct] |
| 173 | command. Individual artifacts can be extracted using the |
| 174 | [/help/artifact | fossil artifact] command. |
| 175 | When accessing the repository database using raw SQL and the |
| 176 | [/help/sqlite3 | fossil sql] command, the extension function |
| 177 | "<tt>content()</tt>" with a single argument which is the SHA1 hash |
| 178 | of an artifact will return the complete undeleted and uncompressed |
| 179 | content of that artifact. |
| 180 | |
| 181 | Going the other way, the [/help/reconstruct | fossil reconstruct] |
| 182 | command will scan a directory hierarchy and add all files found to |
| 183 | a new repository database. The [/help/import | fossil import] command |
| 184 | works by reading the input git-fast-export stream and using it to construct |
| @@ -225,11 +224,11 @@ | |
| 224 | by [/help/sync | fossil sync]. That is because it is entirely reasonable |
| 225 | that two different websites for the same project might have completely |
| 226 | different display preferences and user communities. One instance of the |
| 227 | project might be a fork of the other, for example, which pulls from the |
| 228 | other but never pushes and extends the project in ways that the keepers of |
| 229 | the other website disapprove of. |
| 230 | |
| 231 | Display and processing information includes the following: |
| 232 | |
| 233 | * The name and description of the project |
| 234 | * The CSS file, header, and footer used by all web pages |
| @@ -242,31 +241,31 @@ | |
| 241 | global values defined in the per-user configuration database. |
| 242 | |
| 243 | Though the display and processing preferences do not move between |
| 244 | repository instances using [/help/sync | fossil sync], this information |
| 245 | can be shared between repositories using the |
| 246 | [/help/config | fossil config push] and |
| 247 | [/help/config | fossil config pull] commands. |
| 248 | The display and processing information is also copied into new |
| 249 | repositories when they are created using |
| 250 | [/help/clone | fossil clone]. |
| 251 | |
| 252 | <h4>2.2.4 User Credentials And Privileges</h4> |
| 253 | |
| 254 | Just because two development teams are collaborating on a project and allow |
| 255 | push and/or pull between their repositories does not mean that they |
| 256 | trust each other enough to share passwords and access privileges. |
| 257 | Hence the names and emails and passwords and privileges of users are |
| 258 | considered private information that is kept locally in each repository. |
| 259 | |
| 260 | Each repository database has a table holding the username, privileges, |
| 261 | and login credentials for users authorized to interact with that particular |
| 262 | database. In addition, there is a table named "concealed" that maps the |
| 263 | SHA1 hash of each users email address back into their true email address. |
| 264 | The concealed table allows just the SHA1 hash of email addresses to |
| 265 | be stored in tickets, and thus prevents actual email addresses from falling |
| 266 | into the hands of spammers who happen to clone the repository. |
| 267 | |
| 268 | The content of the user and concealed tables can be pushed and pulled using the |
| 269 | [/help/config | fossil config push] and |
| 270 | [/help/config | fossil config pull] commands with the "user" and |
| 271 | "email" as the AREA argument, but only if you have administrative |
| @@ -278,11 +277,11 @@ | |
| 277 | project - is intended to be an append-only database. In other words, |
| 278 | new artifacts can be added but artifacts can never be removed. But |
| 279 | it sometimes happens that inappropriate content is mistakenly or |
| 280 | maliciously added to a repository. The only way to get rid of |
| 281 | the undesired content is to [./shunning.wiki | "shun"] it. |
| 282 | The "shun" table in the repository database records the SHA1 hash of |
| 283 | all shunned artifacts. |
| 284 | |
| 285 | The shun table can be pushed or pulled using |
| 286 | the [/help/config | fossil config] command with the "shun" AREA argument. |
| 287 | The shun table is also copied during a [/help/clone | clone]. |
| 288 |
+5
| --- www/webpage-ex.md | ||
| +++ www/webpage-ex.md | ||
| @@ -64,10 +64,15 @@ | ||
| 64 | 64 | |
| 65 | 65 | * <a target='_blank' class='exbtn' |
| 66 | 66 | href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>Example</a> |
| 67 | 67 | Show check-ins circa 2014-01-08 by user "drh". |
| 68 | 68 | |
| 69 | + * <a target='_blank' class='exbtn' | |
| 70 | + href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>Example</a> | |
| 71 | + Show all check-ins between version-1.34 and version-1.35 that make | |
| 72 | + changes to either of the files src/timeline.c or src/doc.c. | |
| 73 | + | |
| 69 | 74 | <big><b>→</b></big> (Hint: In the pages above, click the graph nodes |
| 70 | 75 | for any two check-ins or files to see a diff.) |
| 71 | 76 | <big><b>←</b></big> |
| 72 | 77 | |
| 73 | 78 | * <a target='_blank' class='exbtn' |
| 74 | 79 |
| --- www/webpage-ex.md | |
| +++ www/webpage-ex.md | |
| @@ -64,10 +64,15 @@ | |
| 64 | |
| 65 | * <a target='_blank' class='exbtn' |
| 66 | href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>Example</a> |
| 67 | Show check-ins circa 2014-01-08 by user "drh". |
| 68 | |
| 69 | <big><b>→</b></big> (Hint: In the pages above, click the graph nodes |
| 70 | for any two check-ins or files to see a diff.) |
| 71 | <big><b>←</b></big> |
| 72 | |
| 73 | * <a target='_blank' class='exbtn' |
| 74 |
| --- www/webpage-ex.md | |
| +++ www/webpage-ex.md | |
| @@ -64,10 +64,15 @@ | |
| 64 | |
| 65 | * <a target='_blank' class='exbtn' |
| 66 | href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>Example</a> |
| 67 | Show check-ins circa 2014-01-08 by user "drh". |
| 68 | |
| 69 | * <a target='_blank' class='exbtn' |
| 70 | href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>Example</a> |
| 71 | Show all check-ins between version-1.34 and version-1.35 that make |
| 72 | changes to either of the files src/timeline.c or src/doc.c. |
| 73 | |
| 74 | <big><b>→</b></big> (Hint: In the pages above, click the graph nodes |
| 75 | for any two check-ins or files to see a diff.) |
| 76 | <big><b>←</b></big> |
| 77 | |
| 78 | * <a target='_blank' class='exbtn' |
| 79 |