Fossil SCM
Add the "help" command and the "clean" command. More work is needed on the text for various help messages.
Commit
c9fdb846fb169e3789256688942b56e5c4fa390f
Parent
e5b74951d90a0a4…
9 files changed
+4
-1
+43
-12
+7
-1
+3
-2
+10
-5
+2
-7
+5
+53
-14
+69
-2
+4
-1
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -30,12 +30,13 @@ | ||
| 30 | 30 | |
| 31 | 31 | |
| 32 | 32 | /* |
| 33 | 33 | ** COMMAND: add |
| 34 | 34 | ** |
| 35 | +** Usage: %fossil add FILE... | |
| 35 | 36 | ** Add one or more files to the current checkout such that these files |
| 36 | -** will be added to the repository at the next checkin. | |
| 37 | +** will be inserted into the repository at the next commit. | |
| 37 | 38 | */ |
| 38 | 39 | void add_cmd(void){ |
| 39 | 40 | int i; |
| 40 | 41 | int vid; |
| 41 | 42 | |
| @@ -80,10 +81,12 @@ | ||
| 80 | 81 | |
| 81 | 82 | /* |
| 82 | 83 | ** COMMAND: rm |
| 83 | 84 | ** COMMAND: del |
| 84 | 85 | ** |
| 86 | +** Usage: %fossil rm FILE... | |
| 87 | +** or: %fossil del FILE... | |
| 85 | 88 | ** Remove one or more files from the tree. |
| 86 | 89 | */ |
| 87 | 90 | void del_cmd(void){ |
| 88 | 91 | int i; |
| 89 | 92 | int vid; |
| 90 | 93 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -30,12 +30,13 @@ | |
| 30 | |
| 31 | |
| 32 | /* |
| 33 | ** COMMAND: add |
| 34 | ** |
| 35 | ** Add one or more files to the current checkout such that these files |
| 36 | ** will be added to the repository at the next checkin. |
| 37 | */ |
| 38 | void add_cmd(void){ |
| 39 | int i; |
| 40 | int vid; |
| 41 | |
| @@ -80,10 +81,12 @@ | |
| 80 | |
| 81 | /* |
| 82 | ** COMMAND: rm |
| 83 | ** COMMAND: del |
| 84 | ** |
| 85 | ** Remove one or more files from the tree. |
| 86 | */ |
| 87 | void del_cmd(void){ |
| 88 | int i; |
| 89 | int vid; |
| 90 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -30,12 +30,13 @@ | |
| 30 | |
| 31 | |
| 32 | /* |
| 33 | ** COMMAND: add |
| 34 | ** |
| 35 | ** Usage: %fossil add FILE... |
| 36 | ** Add one or more files to the current checkout such that these files |
| 37 | ** will be inserted into the repository at the next commit. |
| 38 | */ |
| 39 | void add_cmd(void){ |
| 40 | int i; |
| 41 | int vid; |
| 42 | |
| @@ -80,10 +81,12 @@ | |
| 81 | |
| 82 | /* |
| 83 | ** COMMAND: rm |
| 84 | ** COMMAND: del |
| 85 | ** |
| 86 | ** Usage: %fossil rm FILE... |
| 87 | ** or: %fossil del FILE... |
| 88 | ** Remove one or more files from the tree. |
| 89 | */ |
| 90 | void del_cmd(void){ |
| 91 | int i; |
| 92 | int vid; |
| 93 |
+43
-12
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -70,11 +70,13 @@ | ||
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | /* |
| 73 | 73 | ** COMMAND: changes |
| 74 | 74 | ** |
| 75 | -** Report on the current status of all files. | |
| 75 | +** Usage: %fossil changes | |
| 76 | +** Report on the edit status of all files in the current checkout. | |
| 77 | +** See also the "status" and "extra" commands. | |
| 76 | 78 | */ |
| 77 | 79 | void changes_cmd(void){ |
| 78 | 80 | Blob report; |
| 79 | 81 | int vid; |
| 80 | 82 | db_must_be_within_tree(); |
| @@ -85,10 +87,12 @@ | ||
| 85 | 87 | blob_write_to_file(&report, "-"); |
| 86 | 88 | } |
| 87 | 89 | |
| 88 | 90 | /* |
| 89 | 91 | ** COMMAND: status |
| 92 | +** Usage: %fossil status | |
| 93 | +** Report on the status of the current checkout. | |
| 90 | 94 | */ |
| 91 | 95 | void status_cmd(void){ |
| 92 | 96 | int vid; |
| 93 | 97 | db_must_be_within_tree(); |
| 94 | 98 | /* 012345678901234 */ |
| @@ -102,12 +106,12 @@ | ||
| 102 | 106 | changes_cmd(); |
| 103 | 107 | } |
| 104 | 108 | |
| 105 | 109 | /* |
| 106 | 110 | ** COMMAND: ls |
| 107 | -** | |
| 108 | -** Show all files currently in the repository | |
| 111 | +** Usage: %fossil ls | |
| 112 | +** Show the names of all files in the current checkout | |
| 109 | 113 | */ |
| 110 | 114 | void ls_cmd(void){ |
| 111 | 115 | int vid; |
| 112 | 116 | Stmt q; |
| 113 | 117 | |
| @@ -134,32 +138,56 @@ | ||
| 134 | 138 | db_finalize(&q); |
| 135 | 139 | } |
| 136 | 140 | |
| 137 | 141 | /* |
| 138 | 142 | ** COMMAND: extra |
| 139 | -** | |
| 143 | +** Usage: %fossil extra | |
| 140 | 144 | ** Print a list of all files in the source tree that are not part of |
| 141 | -** the project | |
| 145 | +** the current checkout. See also the "clean" command. | |
| 142 | 146 | */ |
| 143 | 147 | void extra_cmd(void){ |
| 144 | 148 | Blob path; |
| 145 | 149 | Stmt q; |
| 146 | 150 | db_must_be_within_tree(); |
| 147 | 151 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 148 | 152 | chdir(g.zLocalRoot); |
| 149 | 153 | blob_zero(&path); |
| 150 | 154 | vfile_scan(0, &path); |
| 151 | - db_multi_exec("DELETE FROM sfile WHERE x='FOSSIL'"); | |
| 152 | 155 | db_prepare(&q, |
| 153 | 156 | "SELECT x FROM sfile" |
| 154 | 157 | " WHERE x NOT IN ('manifest','_FOSSIL_')" |
| 155 | 158 | " ORDER BY 1"); |
| 156 | 159 | while( db_step(&q)==SQLITE_ROW ){ |
| 157 | 160 | printf("%s\n", db_column_text(&q, 0)); |
| 158 | 161 | } |
| 159 | 162 | db_finalize(&q); |
| 160 | 163 | } |
| 164 | + | |
| 165 | +/* | |
| 166 | +** COMMAND: clean | |
| 167 | +** Usage: %fossil clean | |
| 168 | +** Delete all "extra" files in the source tree. "Extra" files are | |
| 169 | +** files that are not officially part of the checkout. See also | |
| 170 | +** the "extra" command. | |
| 171 | +*/ | |
| 172 | +void clean_cmd(void){ | |
| 173 | + Blob path; | |
| 174 | + Stmt q; | |
| 175 | + db_must_be_within_tree(); | |
| 176 | + db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); | |
| 177 | + chdir(g.zLocalRoot); | |
| 178 | + blob_zero(&path); | |
| 179 | + vfile_scan(0, &path); | |
| 180 | + db_prepare(&q, | |
| 181 | + "SELECT %Q || x FROM sfile" | |
| 182 | + " WHERE x NOT IN ('manifest','_FOSSIL_')" | |
| 183 | + " ORDER BY 1", g.zLocalRoot); | |
| 184 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 185 | + unlink(db_column_text(&q, 0)); | |
| 186 | + } | |
| 187 | + db_finalize(&q); | |
| 188 | +} | |
| 161 | 189 | |
| 162 | 190 | /* |
| 163 | 191 | ** Prepare a commit comment. Let the user modify it using the |
| 164 | 192 | ** editor specified in the global_config table or either |
| 165 | 193 | ** the VISUAL or EDITOR environment variable. |
| @@ -191,10 +219,11 @@ | ||
| 191 | 219 | } |
| 192 | 220 | zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'", |
| 193 | 221 | g.zLocalRoot); |
| 194 | 222 | blob_write_to_file(&text, zFile); |
| 195 | 223 | zCmd = mprintf("%s %s", zEditor, zFile); |
| 224 | + printf("%s\n", zCmd); | |
| 196 | 225 | if( system(zCmd) ){ |
| 197 | 226 | fossil_panic("editor aborted"); |
| 198 | 227 | } |
| 199 | 228 | blob_reset(&text); |
| 200 | 229 | blob_read_from_file(&text, zFile); |
| @@ -255,17 +284,19 @@ | ||
| 255 | 284 | } |
| 256 | 285 | |
| 257 | 286 | /* |
| 258 | 287 | ** COMMAND: commit |
| 259 | 288 | ** |
| 260 | -** Create a new version containing all of the changes in the current | |
| 261 | -** checkout. A commit is a three step process: | |
| 289 | +** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...? | |
| 262 | 290 | ** |
| 263 | -** 1) Add the new content to the blob table, | |
| 264 | -** 2) Create and add the new manifest to the blob table, | |
| 265 | -** 3) Update the vfile table, | |
| 266 | -** 4) Run checks to make sure everything is still internally consistent. | |
| 291 | +** Create a new version containing all of the changes in the current | |
| 292 | +** checkout. You will be prompted to enter a check-in comment unless | |
| 293 | +** the "-m" option is used to specify a command line. You will be | |
| 294 | +** prompted for your GPG passphrase in order to sign the new manifest | |
| 295 | +** unless the "--nosign" options is used. All files that have | |
| 296 | +** changed will be committed unless some subset of files is specified | |
| 297 | +** on the command line. | |
| 267 | 298 | */ |
| 268 | 299 | void commit_cmd(void){ |
| 269 | 300 | int rc; |
| 270 | 301 | int vid, nrid, nvid; |
| 271 | 302 | Blob comment; |
| 272 | 303 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -70,11 +70,13 @@ | |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | ** COMMAND: changes |
| 74 | ** |
| 75 | ** Report on the current status of all files. |
| 76 | */ |
| 77 | void changes_cmd(void){ |
| 78 | Blob report; |
| 79 | int vid; |
| 80 | db_must_be_within_tree(); |
| @@ -85,10 +87,12 @@ | |
| 85 | blob_write_to_file(&report, "-"); |
| 86 | } |
| 87 | |
| 88 | /* |
| 89 | ** COMMAND: status |
| 90 | */ |
| 91 | void status_cmd(void){ |
| 92 | int vid; |
| 93 | db_must_be_within_tree(); |
| 94 | /* 012345678901234 */ |
| @@ -102,12 +106,12 @@ | |
| 102 | changes_cmd(); |
| 103 | } |
| 104 | |
| 105 | /* |
| 106 | ** COMMAND: ls |
| 107 | ** |
| 108 | ** Show all files currently in the repository |
| 109 | */ |
| 110 | void ls_cmd(void){ |
| 111 | int vid; |
| 112 | Stmt q; |
| 113 | |
| @@ -134,32 +138,56 @@ | |
| 134 | db_finalize(&q); |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | ** COMMAND: extra |
| 139 | ** |
| 140 | ** Print a list of all files in the source tree that are not part of |
| 141 | ** the project |
| 142 | */ |
| 143 | void extra_cmd(void){ |
| 144 | Blob path; |
| 145 | Stmt q; |
| 146 | db_must_be_within_tree(); |
| 147 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 148 | chdir(g.zLocalRoot); |
| 149 | blob_zero(&path); |
| 150 | vfile_scan(0, &path); |
| 151 | db_multi_exec("DELETE FROM sfile WHERE x='FOSSIL'"); |
| 152 | db_prepare(&q, |
| 153 | "SELECT x FROM sfile" |
| 154 | " WHERE x NOT IN ('manifest','_FOSSIL_')" |
| 155 | " ORDER BY 1"); |
| 156 | while( db_step(&q)==SQLITE_ROW ){ |
| 157 | printf("%s\n", db_column_text(&q, 0)); |
| 158 | } |
| 159 | db_finalize(&q); |
| 160 | } |
| 161 | |
| 162 | /* |
| 163 | ** Prepare a commit comment. Let the user modify it using the |
| 164 | ** editor specified in the global_config table or either |
| 165 | ** the VISUAL or EDITOR environment variable. |
| @@ -191,10 +219,11 @@ | |
| 191 | } |
| 192 | zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'", |
| 193 | g.zLocalRoot); |
| 194 | blob_write_to_file(&text, zFile); |
| 195 | zCmd = mprintf("%s %s", zEditor, zFile); |
| 196 | if( system(zCmd) ){ |
| 197 | fossil_panic("editor aborted"); |
| 198 | } |
| 199 | blob_reset(&text); |
| 200 | blob_read_from_file(&text, zFile); |
| @@ -255,17 +284,19 @@ | |
| 255 | } |
| 256 | |
| 257 | /* |
| 258 | ** COMMAND: commit |
| 259 | ** |
| 260 | ** Create a new version containing all of the changes in the current |
| 261 | ** checkout. A commit is a three step process: |
| 262 | ** |
| 263 | ** 1) Add the new content to the blob table, |
| 264 | ** 2) Create and add the new manifest to the blob table, |
| 265 | ** 3) Update the vfile table, |
| 266 | ** 4) Run checks to make sure everything is still internally consistent. |
| 267 | */ |
| 268 | void commit_cmd(void){ |
| 269 | int rc; |
| 270 | int vid, nrid, nvid; |
| 271 | Blob comment; |
| 272 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -70,11 +70,13 @@ | |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | ** COMMAND: changes |
| 74 | ** |
| 75 | ** Usage: %fossil changes |
| 76 | ** Report on the edit status of all files in the current checkout. |
| 77 | ** See also the "status" and "extra" commands. |
| 78 | */ |
| 79 | void changes_cmd(void){ |
| 80 | Blob report; |
| 81 | int vid; |
| 82 | db_must_be_within_tree(); |
| @@ -85,10 +87,12 @@ | |
| 87 | blob_write_to_file(&report, "-"); |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | ** COMMAND: status |
| 92 | ** Usage: %fossil status |
| 93 | ** Report on the status of the current checkout. |
| 94 | */ |
| 95 | void status_cmd(void){ |
| 96 | int vid; |
| 97 | db_must_be_within_tree(); |
| 98 | /* 012345678901234 */ |
| @@ -102,12 +106,12 @@ | |
| 106 | changes_cmd(); |
| 107 | } |
| 108 | |
| 109 | /* |
| 110 | ** COMMAND: ls |
| 111 | ** Usage: %fossil ls |
| 112 | ** Show the names of all files in the current checkout |
| 113 | */ |
| 114 | void ls_cmd(void){ |
| 115 | int vid; |
| 116 | Stmt q; |
| 117 | |
| @@ -134,32 +138,56 @@ | |
| 138 | db_finalize(&q); |
| 139 | } |
| 140 | |
| 141 | /* |
| 142 | ** COMMAND: extra |
| 143 | ** Usage: %fossil extra |
| 144 | ** Print a list of all files in the source tree that are not part of |
| 145 | ** the current checkout. See also the "clean" command. |
| 146 | */ |
| 147 | void extra_cmd(void){ |
| 148 | Blob path; |
| 149 | Stmt q; |
| 150 | db_must_be_within_tree(); |
| 151 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 152 | chdir(g.zLocalRoot); |
| 153 | blob_zero(&path); |
| 154 | vfile_scan(0, &path); |
| 155 | db_prepare(&q, |
| 156 | "SELECT x FROM sfile" |
| 157 | " WHERE x NOT IN ('manifest','_FOSSIL_')" |
| 158 | " ORDER BY 1"); |
| 159 | while( db_step(&q)==SQLITE_ROW ){ |
| 160 | printf("%s\n", db_column_text(&q, 0)); |
| 161 | } |
| 162 | db_finalize(&q); |
| 163 | } |
| 164 | |
| 165 | /* |
| 166 | ** COMMAND: clean |
| 167 | ** Usage: %fossil clean |
| 168 | ** Delete all "extra" files in the source tree. "Extra" files are |
| 169 | ** files that are not officially part of the checkout. See also |
| 170 | ** the "extra" command. |
| 171 | */ |
| 172 | void clean_cmd(void){ |
| 173 | Blob path; |
| 174 | Stmt q; |
| 175 | db_must_be_within_tree(); |
| 176 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 177 | chdir(g.zLocalRoot); |
| 178 | blob_zero(&path); |
| 179 | vfile_scan(0, &path); |
| 180 | db_prepare(&q, |
| 181 | "SELECT %Q || x FROM sfile" |
| 182 | " WHERE x NOT IN ('manifest','_FOSSIL_')" |
| 183 | " ORDER BY 1", g.zLocalRoot); |
| 184 | while( db_step(&q)==SQLITE_ROW ){ |
| 185 | unlink(db_column_text(&q, 0)); |
| 186 | } |
| 187 | db_finalize(&q); |
| 188 | } |
| 189 | |
| 190 | /* |
| 191 | ** Prepare a commit comment. Let the user modify it using the |
| 192 | ** editor specified in the global_config table or either |
| 193 | ** the VISUAL or EDITOR environment variable. |
| @@ -191,10 +219,11 @@ | |
| 219 | } |
| 220 | zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'", |
| 221 | g.zLocalRoot); |
| 222 | blob_write_to_file(&text, zFile); |
| 223 | zCmd = mprintf("%s %s", zEditor, zFile); |
| 224 | printf("%s\n", zCmd); |
| 225 | if( system(zCmd) ){ |
| 226 | fossil_panic("editor aborted"); |
| 227 | } |
| 228 | blob_reset(&text); |
| 229 | blob_read_from_file(&text, zFile); |
| @@ -255,17 +284,19 @@ | |
| 284 | } |
| 285 | |
| 286 | /* |
| 287 | ** COMMAND: commit |
| 288 | ** |
| 289 | ** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...? |
| 290 | ** |
| 291 | ** Create a new version containing all of the changes in the current |
| 292 | ** checkout. You will be prompted to enter a check-in comment unless |
| 293 | ** the "-m" option is used to specify a command line. You will be |
| 294 | ** prompted for your GPG passphrase in order to sign the new manifest |
| 295 | ** unless the "--nosign" options is used. All files that have |
| 296 | ** changed will be committed unless some subset of files is specified |
| 297 | ** on the command line. |
| 298 | */ |
| 299 | void commit_cmd(void){ |
| 300 | int rc; |
| 301 | int vid, nrid, nvid; |
| 302 | Blob comment; |
| 303 |
+7
-1
| --- src/checkout.c | ||
| +++ src/checkout.c | ||
| @@ -109,11 +109,16 @@ | ||
| 109 | 109 | } |
| 110 | 110 | |
| 111 | 111 | /* |
| 112 | 112 | ** COMMAND: checkout |
| 113 | 113 | ** |
| 114 | -** Check out a version specified on the command-line. | |
| 114 | +** Usage: %fossil checkout VERSION ?-f|--force? | |
| 115 | +** Check out a version specified on the command-line. This command | |
| 116 | +** will not overwrite edited files in the current checkout unless | |
| 117 | +** the --force option appears on the command-line. | |
| 118 | +** | |
| 119 | +** See also the "update" command. | |
| 115 | 120 | */ |
| 116 | 121 | void checkout_cmd(void){ |
| 117 | 122 | int forceFlag; |
| 118 | 123 | int noWrite; |
| 119 | 124 | int vid, prior; |
| @@ -159,10 +164,11 @@ | ||
| 159 | 164 | } |
| 160 | 165 | |
| 161 | 166 | /* |
| 162 | 167 | ** COMMAND: close |
| 163 | 168 | ** |
| 169 | +** Usage: %fossil close ?-f|--force? | |
| 164 | 170 | ** The opposite of "open". Close the current database connection. |
| 165 | 171 | ** Require a -f or --force flag if there are unsaved changed in the |
| 166 | 172 | ** current check-out. |
| 167 | 173 | */ |
| 168 | 174 | void close_cmd(void){ |
| 169 | 175 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -109,11 +109,16 @@ | |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | ** COMMAND: checkout |
| 113 | ** |
| 114 | ** Check out a version specified on the command-line. |
| 115 | */ |
| 116 | void checkout_cmd(void){ |
| 117 | int forceFlag; |
| 118 | int noWrite; |
| 119 | int vid, prior; |
| @@ -159,10 +164,11 @@ | |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | ** COMMAND: close |
| 163 | ** |
| 164 | ** The opposite of "open". Close the current database connection. |
| 165 | ** Require a -f or --force flag if there are unsaved changed in the |
| 166 | ** current check-out. |
| 167 | */ |
| 168 | void close_cmd(void){ |
| 169 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -109,11 +109,16 @@ | |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | ** COMMAND: checkout |
| 113 | ** |
| 114 | ** Usage: %fossil checkout VERSION ?-f|--force? |
| 115 | ** Check out a version specified on the command-line. This command |
| 116 | ** will not overwrite edited files in the current checkout unless |
| 117 | ** the --force option appears on the command-line. |
| 118 | ** |
| 119 | ** See also the "update" command. |
| 120 | */ |
| 121 | void checkout_cmd(void){ |
| 122 | int forceFlag; |
| 123 | int noWrite; |
| 124 | int vid, prior; |
| @@ -159,10 +164,11 @@ | |
| 164 | } |
| 165 | |
| 166 | /* |
| 167 | ** COMMAND: close |
| 168 | ** |
| 169 | ** Usage: %fossil close ?-f|--force? |
| 170 | ** The opposite of "open". Close the current database connection. |
| 171 | ** Require a -f or --force flag if there are unsaved changed in the |
| 172 | ** current check-out. |
| 173 | */ |
| 174 | void close_cmd(void){ |
| 175 |
+3
-2
| --- src/clone.c | ||
| +++ src/clone.c | ||
| @@ -30,13 +30,14 @@ | ||
| 30 | 30 | |
| 31 | 31 | |
| 32 | 32 | /* |
| 33 | 33 | ** COMMAND: clone |
| 34 | 34 | ** |
| 35 | -** Make a clone of a repository in the local directory | |
| 35 | +** Usage: %fossil clone URL FILENAME | |
| 36 | 36 | ** |
| 37 | -** fossil clone FILE-OR-URL NEWDATABASE | |
| 37 | +** Make a clone of a repository specified by URL in the local | |
| 38 | +** file named FILENAME. | |
| 38 | 39 | */ |
| 39 | 40 | void clone_cmd(void){ |
| 40 | 41 | if( g.argc!=4 ){ |
| 41 | 42 | usage("FILE-OR-URL NEW-REPOSITORY"); |
| 42 | 43 | } |
| 43 | 44 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -30,13 +30,14 @@ | |
| 30 | |
| 31 | |
| 32 | /* |
| 33 | ** COMMAND: clone |
| 34 | ** |
| 35 | ** Make a clone of a repository in the local directory |
| 36 | ** |
| 37 | ** fossil clone FILE-OR-URL NEWDATABASE |
| 38 | */ |
| 39 | void clone_cmd(void){ |
| 40 | if( g.argc!=4 ){ |
| 41 | usage("FILE-OR-URL NEW-REPOSITORY"); |
| 42 | } |
| 43 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -30,13 +30,14 @@ | |
| 30 | |
| 31 | |
| 32 | /* |
| 33 | ** COMMAND: clone |
| 34 | ** |
| 35 | ** Usage: %fossil clone URL FILENAME |
| 36 | ** |
| 37 | ** Make a clone of a repository specified by URL in the local |
| 38 | ** file named FILENAME. |
| 39 | */ |
| 40 | void clone_cmd(void){ |
| 41 | if( g.argc!=4 ){ |
| 42 | usage("FILE-OR-URL NEW-REPOSITORY"); |
| 43 | } |
| 44 |
M
src/db.c
+10
-5
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -103,12 +103,11 @@ | ||
| 103 | 103 | /* |
| 104 | 104 | ** Prepare or reprepare the sqlite3 statement from the raw SQL text. |
| 105 | 105 | */ |
| 106 | 106 | static void reprepare(Stmt *pStmt){ |
| 107 | 107 | sqlite3_stmt *pNew; |
| 108 | - int rc; | |
| 109 | - if( (rc = sqlite3_prepare(g.db, blob_buffer(&pStmt->sql), -1, &pNew, 0))!=0 ){ | |
| 108 | + if( sqlite3_prepare(g.db, blob_buffer(&pStmt->sql), -1, &pNew, 0)!=0 ){ | |
| 110 | 109 | db_err("%s\n%s", blob_str(&pStmt->sql), sqlite3_errmsg(g.db)); |
| 111 | 110 | } |
| 112 | 111 | if( pStmt->pStmt ){ |
| 113 | 112 | sqlite3_transfer_bindings(pStmt->pStmt, pNew); |
| 114 | 113 | sqlite3_finalize(pStmt->pStmt); |
| @@ -191,11 +190,11 @@ | ||
| 191 | 190 | /* |
| 192 | 191 | ** Step the SQL statement. Return either SQLITE_ROW or an error code |
| 193 | 192 | ** or SQLITE_OK if the statement finishes successfully. |
| 194 | 193 | */ |
| 195 | 194 | int db_step(Stmt *pStmt){ |
| 196 | - int rc; | |
| 195 | + int rc = SQLITE_OK; | |
| 197 | 196 | int limit = 3; |
| 198 | 197 | while( limit-- ){ |
| 199 | 198 | rc = sqlite3_step(pStmt->pStmt); |
| 200 | 199 | if( rc==SQLITE_ERROR ){ |
| 201 | 200 | rc = sqlite3_reset(pStmt->pStmt); |
| @@ -647,11 +646,14 @@ | ||
| 647 | 646 | |
| 648 | 647 | |
| 649 | 648 | /* |
| 650 | 649 | ** COMMAND: new |
| 651 | 650 | ** |
| 652 | -** Create a new repository | |
| 651 | +** Usage: %fossil new FILENAME | |
| 652 | +** Create a repository for a new project in the file named FILENAME. | |
| 653 | +** This command is distinct from "clone". The "clone" command makes | |
| 654 | +** a copy of an existing project. This command starts a new project. | |
| 653 | 655 | */ |
| 654 | 656 | void create_repository_cmd(void){ |
| 655 | 657 | char *zDate; |
| 656 | 658 | char *zUser; |
| 657 | 659 | Blob hash; |
| @@ -821,11 +823,14 @@ | ||
| 821 | 823 | } |
| 822 | 824 | |
| 823 | 825 | /* |
| 824 | 826 | ** COMMAND: open |
| 825 | 827 | ** |
| 826 | -** Create a new local repository. | |
| 828 | +** Usage: open FILENAME | |
| 829 | +** Open a connection to the local repository in FILENAME. A checkout | |
| 830 | +** for the repository is created with its root at the working directory. | |
| 831 | +** See also the "close" command. | |
| 827 | 832 | */ |
| 828 | 833 | void cmd_open(void){ |
| 829 | 834 | Blob path; |
| 830 | 835 | if( g.argc!=3 ){ |
| 831 | 836 | usage("REPOSITORY-FILENAME"); |
| 832 | 837 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -103,12 +103,11 @@ | |
| 103 | /* |
| 104 | ** Prepare or reprepare the sqlite3 statement from the raw SQL text. |
| 105 | */ |
| 106 | static void reprepare(Stmt *pStmt){ |
| 107 | sqlite3_stmt *pNew; |
| 108 | int rc; |
| 109 | if( (rc = sqlite3_prepare(g.db, blob_buffer(&pStmt->sql), -1, &pNew, 0))!=0 ){ |
| 110 | db_err("%s\n%s", blob_str(&pStmt->sql), sqlite3_errmsg(g.db)); |
| 111 | } |
| 112 | if( pStmt->pStmt ){ |
| 113 | sqlite3_transfer_bindings(pStmt->pStmt, pNew); |
| 114 | sqlite3_finalize(pStmt->pStmt); |
| @@ -191,11 +190,11 @@ | |
| 191 | /* |
| 192 | ** Step the SQL statement. Return either SQLITE_ROW or an error code |
| 193 | ** or SQLITE_OK if the statement finishes successfully. |
| 194 | */ |
| 195 | int db_step(Stmt *pStmt){ |
| 196 | int rc; |
| 197 | int limit = 3; |
| 198 | while( limit-- ){ |
| 199 | rc = sqlite3_step(pStmt->pStmt); |
| 200 | if( rc==SQLITE_ERROR ){ |
| 201 | rc = sqlite3_reset(pStmt->pStmt); |
| @@ -647,11 +646,14 @@ | |
| 647 | |
| 648 | |
| 649 | /* |
| 650 | ** COMMAND: new |
| 651 | ** |
| 652 | ** Create a new repository |
| 653 | */ |
| 654 | void create_repository_cmd(void){ |
| 655 | char *zDate; |
| 656 | char *zUser; |
| 657 | Blob hash; |
| @@ -821,11 +823,14 @@ | |
| 821 | } |
| 822 | |
| 823 | /* |
| 824 | ** COMMAND: open |
| 825 | ** |
| 826 | ** Create a new local repository. |
| 827 | */ |
| 828 | void cmd_open(void){ |
| 829 | Blob path; |
| 830 | if( g.argc!=3 ){ |
| 831 | usage("REPOSITORY-FILENAME"); |
| 832 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -103,12 +103,11 @@ | |
| 103 | /* |
| 104 | ** Prepare or reprepare the sqlite3 statement from the raw SQL text. |
| 105 | */ |
| 106 | static void reprepare(Stmt *pStmt){ |
| 107 | sqlite3_stmt *pNew; |
| 108 | if( sqlite3_prepare(g.db, blob_buffer(&pStmt->sql), -1, &pNew, 0)!=0 ){ |
| 109 | db_err("%s\n%s", blob_str(&pStmt->sql), sqlite3_errmsg(g.db)); |
| 110 | } |
| 111 | if( pStmt->pStmt ){ |
| 112 | sqlite3_transfer_bindings(pStmt->pStmt, pNew); |
| 113 | sqlite3_finalize(pStmt->pStmt); |
| @@ -191,11 +190,11 @@ | |
| 190 | /* |
| 191 | ** Step the SQL statement. Return either SQLITE_ROW or an error code |
| 192 | ** or SQLITE_OK if the statement finishes successfully. |
| 193 | */ |
| 194 | int db_step(Stmt *pStmt){ |
| 195 | int rc = SQLITE_OK; |
| 196 | int limit = 3; |
| 197 | while( limit-- ){ |
| 198 | rc = sqlite3_step(pStmt->pStmt); |
| 199 | if( rc==SQLITE_ERROR ){ |
| 200 | rc = sqlite3_reset(pStmt->pStmt); |
| @@ -647,11 +646,14 @@ | |
| 646 | |
| 647 | |
| 648 | /* |
| 649 | ** COMMAND: new |
| 650 | ** |
| 651 | ** Usage: %fossil new FILENAME |
| 652 | ** Create a repository for a new project in the file named FILENAME. |
| 653 | ** This command is distinct from "clone". The "clone" command makes |
| 654 | ** a copy of an existing project. This command starts a new project. |
| 655 | */ |
| 656 | void create_repository_cmd(void){ |
| 657 | char *zDate; |
| 658 | char *zUser; |
| 659 | Blob hash; |
| @@ -821,11 +823,14 @@ | |
| 823 | } |
| 824 | |
| 825 | /* |
| 826 | ** COMMAND: open |
| 827 | ** |
| 828 | ** Usage: open FILENAME |
| 829 | ** Open a connection to the local repository in FILENAME. A checkout |
| 830 | ** for the repository is created with its root at the working directory. |
| 831 | ** See also the "close" command. |
| 832 | */ |
| 833 | void cmd_open(void){ |
| 834 | Blob path; |
| 835 | if( g.argc!=3 ){ |
| 836 | usage("REPOSITORY-FILENAME"); |
| 837 |
+2
-7
| --- src/descendents.c | ||
| +++ src/descendents.c | ||
| @@ -65,10 +65,11 @@ | ||
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | /* |
| 68 | 68 | ** COMMAND: leaves |
| 69 | 69 | ** |
| 70 | +** Usage: %fossil leaves ?UUID? | |
| 70 | 71 | ** Find all leaf descendents of the current version or of the |
| 71 | 72 | ** specified version. |
| 72 | 73 | */ |
| 73 | 74 | void leaves_cmd(void){ |
| 74 | 75 | Stmt q; |
| @@ -94,23 +95,17 @@ | ||
| 94 | 95 | } |
| 95 | 96 | |
| 96 | 97 | /* |
| 97 | 98 | ** COMMAND: branches |
| 98 | 99 | ** |
| 100 | +** Usage: %fossil branches | |
| 99 | 101 | ** Find leaves of all branches. |
| 100 | 102 | */ |
| 101 | 103 | void branches_cmd(void){ |
| 102 | 104 | Stmt q; |
| 103 | - int base; | |
| 104 | 105 | |
| 105 | 106 | db_must_be_within_tree(); |
| 106 | - if( g.argc==2 ){ | |
| 107 | - base = db_lget_int("checkout", 0); | |
| 108 | - }else{ | |
| 109 | - base = name_to_rid(g.argv[2]); | |
| 110 | - } | |
| 111 | - if( base==0 ) return; | |
| 112 | 107 | db_prepare(&q, |
| 113 | 108 | "SELECT blob.uuid, datetime(event.mtime,'localtime'), event.comment" |
| 114 | 109 | " FROM blob, event" |
| 115 | 110 | " WHERE blob.rid IN" |
| 116 | 111 | " (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)" |
| 117 | 112 |
| --- src/descendents.c | |
| +++ src/descendents.c | |
| @@ -65,10 +65,11 @@ | |
| 65 | } |
| 66 | |
| 67 | /* |
| 68 | ** COMMAND: leaves |
| 69 | ** |
| 70 | ** Find all leaf descendents of the current version or of the |
| 71 | ** specified version. |
| 72 | */ |
| 73 | void leaves_cmd(void){ |
| 74 | Stmt q; |
| @@ -94,23 +95,17 @@ | |
| 94 | } |
| 95 | |
| 96 | /* |
| 97 | ** COMMAND: branches |
| 98 | ** |
| 99 | ** Find leaves of all branches. |
| 100 | */ |
| 101 | void branches_cmd(void){ |
| 102 | Stmt q; |
| 103 | int base; |
| 104 | |
| 105 | db_must_be_within_tree(); |
| 106 | if( g.argc==2 ){ |
| 107 | base = db_lget_int("checkout", 0); |
| 108 | }else{ |
| 109 | base = name_to_rid(g.argv[2]); |
| 110 | } |
| 111 | if( base==0 ) return; |
| 112 | db_prepare(&q, |
| 113 | "SELECT blob.uuid, datetime(event.mtime,'localtime'), event.comment" |
| 114 | " FROM blob, event" |
| 115 | " WHERE blob.rid IN" |
| 116 | " (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)" |
| 117 |
| --- src/descendents.c | |
| +++ src/descendents.c | |
| @@ -65,10 +65,11 @@ | |
| 65 | } |
| 66 | |
| 67 | /* |
| 68 | ** COMMAND: leaves |
| 69 | ** |
| 70 | ** Usage: %fossil leaves ?UUID? |
| 71 | ** Find all leaf descendents of the current version or of the |
| 72 | ** specified version. |
| 73 | */ |
| 74 | void leaves_cmd(void){ |
| 75 | Stmt q; |
| @@ -94,23 +95,17 @@ | |
| 95 | } |
| 96 | |
| 97 | /* |
| 98 | ** COMMAND: branches |
| 99 | ** |
| 100 | ** Usage: %fossil branches |
| 101 | ** Find leaves of all branches. |
| 102 | */ |
| 103 | void branches_cmd(void){ |
| 104 | Stmt q; |
| 105 | |
| 106 | db_must_be_within_tree(); |
| 107 | db_prepare(&q, |
| 108 | "SELECT blob.uuid, datetime(event.mtime,'localtime'), event.comment" |
| 109 | " FROM blob, event" |
| 110 | " WHERE blob.rid IN" |
| 111 | " (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)" |
| 112 |
+5
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -45,10 +45,15 @@ | ||
| 45 | 45 | |
| 46 | 46 | |
| 47 | 47 | /* |
| 48 | 48 | ** COMMAND: diff |
| 49 | 49 | ** COMMAND: tkdiff |
| 50 | +** | |
| 51 | +** Usage: %fossil diff|tkdiff FILE... | |
| 52 | +** Show the difference between the current version of a file (as it | |
| 53 | +** exists on disk) and that same file as it was checked out. Use | |
| 54 | +** either "diff -u" or "tkdiff". | |
| 50 | 55 | */ |
| 51 | 56 | void diff_cmd(void){ |
| 52 | 57 | const char *zFile; |
| 53 | 58 | Blob cmd; |
| 54 | 59 | Blob fname; |
| 55 | 60 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -45,10 +45,15 @@ | |
| 45 | |
| 46 | |
| 47 | /* |
| 48 | ** COMMAND: diff |
| 49 | ** COMMAND: tkdiff |
| 50 | */ |
| 51 | void diff_cmd(void){ |
| 52 | const char *zFile; |
| 53 | Blob cmd; |
| 54 | Blob fname; |
| 55 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -45,10 +45,15 @@ | |
| 45 | |
| 46 | |
| 47 | /* |
| 48 | ** COMMAND: diff |
| 49 | ** COMMAND: tkdiff |
| 50 | ** |
| 51 | ** Usage: %fossil diff|tkdiff FILE... |
| 52 | ** Show the difference between the current version of a file (as it |
| 53 | ** exists on disk) and that same file as it was checked out. Use |
| 54 | ** either "diff -u" or "tkdiff". |
| 55 | */ |
| 56 | void diff_cmd(void){ |
| 57 | const char *zFile; |
| 58 | Blob cmd; |
| 59 | Blob fname; |
| 60 |
+53
-14
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -135,11 +135,11 @@ | ||
| 135 | 135 | */ |
| 136 | 136 | static int name_search( |
| 137 | 137 | const char *zName, /* The name we are looking for */ |
| 138 | 138 | const NameMap *aMap, /* Search in this array */ |
| 139 | 139 | int nMap, /* Number of slots in aMap[] */ |
| 140 | - void (**pxFunc)(void) /* Write pointer to handler function here */ | |
| 140 | + int *pIndex /* OUT: The index in aMap[] of the match */ | |
| 141 | 141 | ){ |
| 142 | 142 | int upr, lwr, cnt, m, i; |
| 143 | 143 | int n = strlen(zName); |
| 144 | 144 | lwr = 0; |
| 145 | 145 | upr = nMap-1; |
| @@ -146,11 +146,11 @@ | ||
| 146 | 146 | while( lwr<=upr ){ |
| 147 | 147 | int mid, c; |
| 148 | 148 | mid = (upr+lwr)/2; |
| 149 | 149 | c = strcmp(zName, aMap[mid].zName); |
| 150 | 150 | if( c==0 ){ |
| 151 | - *pxFunc = aMap[mid].xFunc; | |
| 151 | + *pIndex = mid; | |
| 152 | 152 | return 0; |
| 153 | 153 | }else if( c<0 ){ |
| 154 | 154 | upr = mid - 1; |
| 155 | 155 | }else{ |
| 156 | 156 | lwr = mid + 1; |
| @@ -162,11 +162,11 @@ | ||
| 162 | 162 | m = i; |
| 163 | 163 | cnt++; |
| 164 | 164 | } |
| 165 | 165 | } |
| 166 | 166 | if( cnt==1 ){ |
| 167 | - *pxFunc = aMap[m].xFunc; | |
| 167 | + *pIndex = m; | |
| 168 | 168 | return 0; |
| 169 | 169 | } |
| 170 | 170 | return 1+(cnt>1); |
| 171 | 171 | } |
| 172 | 172 | |
| @@ -174,11 +174,11 @@ | ||
| 174 | 174 | /* |
| 175 | 175 | ** This procedure runs first. |
| 176 | 176 | */ |
| 177 | 177 | int main(int argc, char **argv){ |
| 178 | 178 | const char *zCmdName; |
| 179 | - void (*xFunc)(void); | |
| 179 | + int idx; | |
| 180 | 180 | int rc; |
| 181 | 181 | |
| 182 | 182 | g.now = time(0); |
| 183 | 183 | g.argc = argc; |
| 184 | 184 | g.argv = argv; |
| @@ -192,11 +192,11 @@ | ||
| 192 | 192 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 193 | 193 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 194 | 194 | g.zLogin = find_option("user", "U", 1); |
| 195 | 195 | zCmdName = argv[1]; |
| 196 | 196 | } |
| 197 | - rc = name_search(zCmdName, aCommand, count(aCommand), &xFunc); | |
| 197 | + rc = name_search(zCmdName, aCommand, count(aCommand), &idx); | |
| 198 | 198 | if( rc==1 ){ |
| 199 | 199 | fprintf(stderr,"%s: unknown command: %s\n" |
| 200 | 200 | "%s: use \"commands\" or \"test-commands\" for help\n", |
| 201 | 201 | argv[0], zCmdName, argv[0]); |
| 202 | 202 | return 1; |
| @@ -204,11 +204,11 @@ | ||
| 204 | 204 | fprintf(stderr,"%s: ambiguous command prefix: %s\n" |
| 205 | 205 | "%s: use \"commands\" or \"test-commands\" for help\n", |
| 206 | 206 | argv[0], zCmdName, argv[0]); |
| 207 | 207 | return 1; |
| 208 | 208 | } |
| 209 | - xFunc(); | |
| 209 | + aCommand[idx].xFunc(); | |
| 210 | 210 | return 0; |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | /* |
| 214 | 214 | ** Print an error message, rollback all databases, and quit. |
| @@ -340,39 +340,78 @@ | ||
| 340 | 340 | } |
| 341 | 341 | |
| 342 | 342 | /* |
| 343 | 343 | ** COMMAND: commands |
| 344 | 344 | ** |
| 345 | -** List all commands whose name does not start with "test-" | |
| 345 | +** Usage: %fossil commands | |
| 346 | +** List all supported commands. | |
| 346 | 347 | */ |
| 347 | 348 | void cmd_cmd_list(void){ |
| 348 | 349 | int i, nCmd; |
| 349 | 350 | const char *aCmd[count(aCommand)]; |
| 350 | 351 | for(i=nCmd=0; i<count(aCommand); i++){ |
| 351 | 352 | if( strncmp(aCommand[i].zName,"test",4)==0 ) continue; |
| 352 | - if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; | |
| 353 | + /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */ | |
| 353 | 354 | aCmd[nCmd++] = aCommand[i].zName; |
| 354 | 355 | } |
| 355 | 356 | multi_column_list(aCmd, nCmd); |
| 356 | 357 | } |
| 357 | 358 | |
| 358 | 359 | /* |
| 359 | 360 | ** COMMAND: test-commands |
| 360 | 361 | ** |
| 361 | -** List all commands whose name begins with "test" | |
| 362 | +** Usage: %fossil test-commands | |
| 363 | +** List all commands used for testing and debugging. | |
| 362 | 364 | */ |
| 363 | 365 | void cmd_test_cmd_list(void){ |
| 364 | 366 | int i, nCmd; |
| 365 | 367 | const char *aCmd[count(aCommand)]; |
| 366 | 368 | for(i=nCmd=0; i<count(aCommand); i++){ |
| 367 | 369 | if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue; |
| 368 | - if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; | |
| 370 | + /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */ | |
| 369 | 371 | aCmd[nCmd++] = aCommand[i].zName; |
| 370 | 372 | } |
| 371 | 373 | multi_column_list(aCmd, nCmd); |
| 372 | 374 | } |
| 373 | 375 | |
| 376 | + | |
| 377 | +/* | |
| 378 | +** COMMAND: help | |
| 379 | +** | |
| 380 | +** Usage: %fossil help COMMAND | |
| 381 | +** Display information on how to use COMMAND | |
| 382 | +*/ | |
| 383 | +void help_cmd(void){ | |
| 384 | + int rc, idx; | |
| 385 | + const char *z; | |
| 386 | + if( g.argc!=3 ){ | |
| 387 | + printf("Usage: %s help <command>.\nAvailable commands:\n", g.argv[0]); | |
| 388 | + cmd_cmd_list(); | |
| 389 | + return; | |
| 390 | + } | |
| 391 | + rc = name_search(g.argv[2], aCommand, count(aCommand), &idx); | |
| 392 | + if( rc==1 ){ | |
| 393 | + fossil_fatal("unknown command: %s", g.argv[2]); | |
| 394 | + }else if( rc==2 ){ | |
| 395 | + fossil_fatal("ambiguous command prefix: %s", g.argv[2]); | |
| 396 | + } | |
| 397 | + z = aCmdHelp[idx]; | |
| 398 | + if( z==0 ){ | |
| 399 | + fossil_fatal("no help available for the %s command", | |
| 400 | + aCommand[idx].zName); | |
| 401 | + } | |
| 402 | + while( *z ){ | |
| 403 | + if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ | |
| 404 | + printf("%s", g.argv[0]); | |
| 405 | + z += 7; | |
| 406 | + }else{ | |
| 407 | + putchar(*z); | |
| 408 | + z++; | |
| 409 | + } | |
| 410 | + } | |
| 411 | + putchar('\n'); | |
| 412 | +} | |
| 374 | 413 | |
| 375 | 414 | /* |
| 376 | 415 | ** RSS feeds need to reference absolute URLs so we need to calculate |
| 377 | 416 | ** the base URL onto which we add components. This is basically |
| 378 | 417 | ** cgi_redirect() stripped down and always returning an absolute URL. |
| @@ -412,11 +451,11 @@ | ||
| 412 | 451 | ** environment variable. |
| 413 | 452 | */ |
| 414 | 453 | static void process_one_web_page(void){ |
| 415 | 454 | const char *zPathInfo; |
| 416 | 455 | char *zPath; |
| 417 | - void (*xFunc)(void); | |
| 456 | + int idx; | |
| 418 | 457 | int i, j; |
| 419 | 458 | |
| 420 | 459 | /* Find the page that the user has requested, construct and deliver that |
| 421 | 460 | ** page. |
| 422 | 461 | */ |
| @@ -463,17 +502,17 @@ | ||
| 463 | 502 | } |
| 464 | 503 | |
| 465 | 504 | /* Locate the method specified by the path and execute the function |
| 466 | 505 | ** that implements that method. |
| 467 | 506 | */ |
| 468 | - if( name_search(g.zPath, aWebpage, count(aWebpage), &xFunc) && | |
| 469 | - name_search("not_found", aWebpage, count(aWebpage), &xFunc) ){ | |
| 507 | + if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) && | |
| 508 | + name_search("not_found", aWebpage, count(aWebpage), &idx) ){ | |
| 470 | 509 | cgi_set_status(404,"Not Found"); |
| 471 | 510 | @ <h1>Not Found</h1> |
| 472 | 511 | @ <p>Page not found: %h(g.zPath)</p> |
| 473 | 512 | }else{ |
| 474 | - xFunc(); | |
| 513 | + aWebpage[idx].xFunc(); | |
| 475 | 514 | } |
| 476 | 515 | |
| 477 | 516 | /* Return the result. |
| 478 | 517 | */ |
| 479 | 518 | cgi_reply(); |
| 480 | 519 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -135,11 +135,11 @@ | |
| 135 | */ |
| 136 | static int name_search( |
| 137 | const char *zName, /* The name we are looking for */ |
| 138 | const NameMap *aMap, /* Search in this array */ |
| 139 | int nMap, /* Number of slots in aMap[] */ |
| 140 | void (**pxFunc)(void) /* Write pointer to handler function here */ |
| 141 | ){ |
| 142 | int upr, lwr, cnt, m, i; |
| 143 | int n = strlen(zName); |
| 144 | lwr = 0; |
| 145 | upr = nMap-1; |
| @@ -146,11 +146,11 @@ | |
| 146 | while( lwr<=upr ){ |
| 147 | int mid, c; |
| 148 | mid = (upr+lwr)/2; |
| 149 | c = strcmp(zName, aMap[mid].zName); |
| 150 | if( c==0 ){ |
| 151 | *pxFunc = aMap[mid].xFunc; |
| 152 | return 0; |
| 153 | }else if( c<0 ){ |
| 154 | upr = mid - 1; |
| 155 | }else{ |
| 156 | lwr = mid + 1; |
| @@ -162,11 +162,11 @@ | |
| 162 | m = i; |
| 163 | cnt++; |
| 164 | } |
| 165 | } |
| 166 | if( cnt==1 ){ |
| 167 | *pxFunc = aMap[m].xFunc; |
| 168 | return 0; |
| 169 | } |
| 170 | return 1+(cnt>1); |
| 171 | } |
| 172 | |
| @@ -174,11 +174,11 @@ | |
| 174 | /* |
| 175 | ** This procedure runs first. |
| 176 | */ |
| 177 | int main(int argc, char **argv){ |
| 178 | const char *zCmdName; |
| 179 | void (*xFunc)(void); |
| 180 | int rc; |
| 181 | |
| 182 | g.now = time(0); |
| 183 | g.argc = argc; |
| 184 | g.argv = argv; |
| @@ -192,11 +192,11 @@ | |
| 192 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 193 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 194 | g.zLogin = find_option("user", "U", 1); |
| 195 | zCmdName = argv[1]; |
| 196 | } |
| 197 | rc = name_search(zCmdName, aCommand, count(aCommand), &xFunc); |
| 198 | if( rc==1 ){ |
| 199 | fprintf(stderr,"%s: unknown command: %s\n" |
| 200 | "%s: use \"commands\" or \"test-commands\" for help\n", |
| 201 | argv[0], zCmdName, argv[0]); |
| 202 | return 1; |
| @@ -204,11 +204,11 @@ | |
| 204 | fprintf(stderr,"%s: ambiguous command prefix: %s\n" |
| 205 | "%s: use \"commands\" or \"test-commands\" for help\n", |
| 206 | argv[0], zCmdName, argv[0]); |
| 207 | return 1; |
| 208 | } |
| 209 | xFunc(); |
| 210 | return 0; |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | ** Print an error message, rollback all databases, and quit. |
| @@ -340,39 +340,78 @@ | |
| 340 | } |
| 341 | |
| 342 | /* |
| 343 | ** COMMAND: commands |
| 344 | ** |
| 345 | ** List all commands whose name does not start with "test-" |
| 346 | */ |
| 347 | void cmd_cmd_list(void){ |
| 348 | int i, nCmd; |
| 349 | const char *aCmd[count(aCommand)]; |
| 350 | for(i=nCmd=0; i<count(aCommand); i++){ |
| 351 | if( strncmp(aCommand[i].zName,"test",4)==0 ) continue; |
| 352 | if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; |
| 353 | aCmd[nCmd++] = aCommand[i].zName; |
| 354 | } |
| 355 | multi_column_list(aCmd, nCmd); |
| 356 | } |
| 357 | |
| 358 | /* |
| 359 | ** COMMAND: test-commands |
| 360 | ** |
| 361 | ** List all commands whose name begins with "test" |
| 362 | */ |
| 363 | void cmd_test_cmd_list(void){ |
| 364 | int i, nCmd; |
| 365 | const char *aCmd[count(aCommand)]; |
| 366 | for(i=nCmd=0; i<count(aCommand); i++){ |
| 367 | if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue; |
| 368 | if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; |
| 369 | aCmd[nCmd++] = aCommand[i].zName; |
| 370 | } |
| 371 | multi_column_list(aCmd, nCmd); |
| 372 | } |
| 373 | |
| 374 | |
| 375 | /* |
| 376 | ** RSS feeds need to reference absolute URLs so we need to calculate |
| 377 | ** the base URL onto which we add components. This is basically |
| 378 | ** cgi_redirect() stripped down and always returning an absolute URL. |
| @@ -412,11 +451,11 @@ | |
| 412 | ** environment variable. |
| 413 | */ |
| 414 | static void process_one_web_page(void){ |
| 415 | const char *zPathInfo; |
| 416 | char *zPath; |
| 417 | void (*xFunc)(void); |
| 418 | int i, j; |
| 419 | |
| 420 | /* Find the page that the user has requested, construct and deliver that |
| 421 | ** page. |
| 422 | */ |
| @@ -463,17 +502,17 @@ | |
| 463 | } |
| 464 | |
| 465 | /* Locate the method specified by the path and execute the function |
| 466 | ** that implements that method. |
| 467 | */ |
| 468 | if( name_search(g.zPath, aWebpage, count(aWebpage), &xFunc) && |
| 469 | name_search("not_found", aWebpage, count(aWebpage), &xFunc) ){ |
| 470 | cgi_set_status(404,"Not Found"); |
| 471 | @ <h1>Not Found</h1> |
| 472 | @ <p>Page not found: %h(g.zPath)</p> |
| 473 | }else{ |
| 474 | xFunc(); |
| 475 | } |
| 476 | |
| 477 | /* Return the result. |
| 478 | */ |
| 479 | cgi_reply(); |
| 480 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -135,11 +135,11 @@ | |
| 135 | */ |
| 136 | static int name_search( |
| 137 | const char *zName, /* The name we are looking for */ |
| 138 | const NameMap *aMap, /* Search in this array */ |
| 139 | int nMap, /* Number of slots in aMap[] */ |
| 140 | int *pIndex /* OUT: The index in aMap[] of the match */ |
| 141 | ){ |
| 142 | int upr, lwr, cnt, m, i; |
| 143 | int n = strlen(zName); |
| 144 | lwr = 0; |
| 145 | upr = nMap-1; |
| @@ -146,11 +146,11 @@ | |
| 146 | while( lwr<=upr ){ |
| 147 | int mid, c; |
| 148 | mid = (upr+lwr)/2; |
| 149 | c = strcmp(zName, aMap[mid].zName); |
| 150 | if( c==0 ){ |
| 151 | *pIndex = mid; |
| 152 | return 0; |
| 153 | }else if( c<0 ){ |
| 154 | upr = mid - 1; |
| 155 | }else{ |
| 156 | lwr = mid + 1; |
| @@ -162,11 +162,11 @@ | |
| 162 | m = i; |
| 163 | cnt++; |
| 164 | } |
| 165 | } |
| 166 | if( cnt==1 ){ |
| 167 | *pIndex = m; |
| 168 | return 0; |
| 169 | } |
| 170 | return 1+(cnt>1); |
| 171 | } |
| 172 | |
| @@ -174,11 +174,11 @@ | |
| 174 | /* |
| 175 | ** This procedure runs first. |
| 176 | */ |
| 177 | int main(int argc, char **argv){ |
| 178 | const char *zCmdName; |
| 179 | int idx; |
| 180 | int rc; |
| 181 | |
| 182 | g.now = time(0); |
| 183 | g.argc = argc; |
| 184 | g.argv = argv; |
| @@ -192,11 +192,11 @@ | |
| 192 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 193 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 194 | g.zLogin = find_option("user", "U", 1); |
| 195 | zCmdName = argv[1]; |
| 196 | } |
| 197 | rc = name_search(zCmdName, aCommand, count(aCommand), &idx); |
| 198 | if( rc==1 ){ |
| 199 | fprintf(stderr,"%s: unknown command: %s\n" |
| 200 | "%s: use \"commands\" or \"test-commands\" for help\n", |
| 201 | argv[0], zCmdName, argv[0]); |
| 202 | return 1; |
| @@ -204,11 +204,11 @@ | |
| 204 | fprintf(stderr,"%s: ambiguous command prefix: %s\n" |
| 205 | "%s: use \"commands\" or \"test-commands\" for help\n", |
| 206 | argv[0], zCmdName, argv[0]); |
| 207 | return 1; |
| 208 | } |
| 209 | aCommand[idx].xFunc(); |
| 210 | return 0; |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | ** Print an error message, rollback all databases, and quit. |
| @@ -340,39 +340,78 @@ | |
| 340 | } |
| 341 | |
| 342 | /* |
| 343 | ** COMMAND: commands |
| 344 | ** |
| 345 | ** Usage: %fossil commands |
| 346 | ** List all supported commands. |
| 347 | */ |
| 348 | void cmd_cmd_list(void){ |
| 349 | int i, nCmd; |
| 350 | const char *aCmd[count(aCommand)]; |
| 351 | for(i=nCmd=0; i<count(aCommand); i++){ |
| 352 | if( strncmp(aCommand[i].zName,"test",4)==0 ) continue; |
| 353 | /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */ |
| 354 | aCmd[nCmd++] = aCommand[i].zName; |
| 355 | } |
| 356 | multi_column_list(aCmd, nCmd); |
| 357 | } |
| 358 | |
| 359 | /* |
| 360 | ** COMMAND: test-commands |
| 361 | ** |
| 362 | ** Usage: %fossil test-commands |
| 363 | ** List all commands used for testing and debugging. |
| 364 | */ |
| 365 | void cmd_test_cmd_list(void){ |
| 366 | int i, nCmd; |
| 367 | const char *aCmd[count(aCommand)]; |
| 368 | for(i=nCmd=0; i<count(aCommand); i++){ |
| 369 | if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue; |
| 370 | /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */ |
| 371 | aCmd[nCmd++] = aCommand[i].zName; |
| 372 | } |
| 373 | multi_column_list(aCmd, nCmd); |
| 374 | } |
| 375 | |
| 376 | |
| 377 | /* |
| 378 | ** COMMAND: help |
| 379 | ** |
| 380 | ** Usage: %fossil help COMMAND |
| 381 | ** Display information on how to use COMMAND |
| 382 | */ |
| 383 | void help_cmd(void){ |
| 384 | int rc, idx; |
| 385 | const char *z; |
| 386 | if( g.argc!=3 ){ |
| 387 | printf("Usage: %s help <command>.\nAvailable commands:\n", g.argv[0]); |
| 388 | cmd_cmd_list(); |
| 389 | return; |
| 390 | } |
| 391 | rc = name_search(g.argv[2], aCommand, count(aCommand), &idx); |
| 392 | if( rc==1 ){ |
| 393 | fossil_fatal("unknown command: %s", g.argv[2]); |
| 394 | }else if( rc==2 ){ |
| 395 | fossil_fatal("ambiguous command prefix: %s", g.argv[2]); |
| 396 | } |
| 397 | z = aCmdHelp[idx]; |
| 398 | if( z==0 ){ |
| 399 | fossil_fatal("no help available for the %s command", |
| 400 | aCommand[idx].zName); |
| 401 | } |
| 402 | while( *z ){ |
| 403 | if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ |
| 404 | printf("%s", g.argv[0]); |
| 405 | z += 7; |
| 406 | }else{ |
| 407 | putchar(*z); |
| 408 | z++; |
| 409 | } |
| 410 | } |
| 411 | putchar('\n'); |
| 412 | } |
| 413 | |
| 414 | /* |
| 415 | ** RSS feeds need to reference absolute URLs so we need to calculate |
| 416 | ** the base URL onto which we add components. This is basically |
| 417 | ** cgi_redirect() stripped down and always returning an absolute URL. |
| @@ -412,11 +451,11 @@ | |
| 451 | ** environment variable. |
| 452 | */ |
| 453 | static void process_one_web_page(void){ |
| 454 | const char *zPathInfo; |
| 455 | char *zPath; |
| 456 | int idx; |
| 457 | int i, j; |
| 458 | |
| 459 | /* Find the page that the user has requested, construct and deliver that |
| 460 | ** page. |
| 461 | */ |
| @@ -463,17 +502,17 @@ | |
| 502 | } |
| 503 | |
| 504 | /* Locate the method specified by the path and execute the function |
| 505 | ** that implements that method. |
| 506 | */ |
| 507 | if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) && |
| 508 | name_search("not_found", aWebpage, count(aWebpage), &idx) ){ |
| 509 | cgi_set_status(404,"Not Found"); |
| 510 | @ <h1>Not Found</h1> |
| 511 | @ <p>Page not found: %h(g.zPath)</p> |
| 512 | }else{ |
| 513 | aWebpage[idx].xFunc(); |
| 514 | } |
| 515 | |
| 516 | /* Return the result. |
| 517 | */ |
| 518 | cgi_reply(); |
| 519 |
+69
-2
| --- src/mkindex.c | ||
| +++ src/mkindex.c | ||
| @@ -55,22 +55,34 @@ | ||
| 55 | 55 | */ |
| 56 | 56 | typedef struct Entry { |
| 57 | 57 | int eType; |
| 58 | 58 | char *zFunc; |
| 59 | 59 | char *zPath; |
| 60 | + char *zHelp; | |
| 60 | 61 | } Entry; |
| 61 | 62 | |
| 62 | 63 | /* |
| 63 | 64 | ** Maximum number of entries |
| 64 | 65 | */ |
| 65 | 66 | #define N_ENTRY 500 |
| 66 | 67 | |
| 68 | +/* | |
| 69 | +** Maximum size of a help message | |
| 70 | +*/ | |
| 71 | +#define MX_HELP 10000 | |
| 72 | + | |
| 67 | 73 | /* |
| 68 | 74 | ** Table of entries |
| 69 | 75 | */ |
| 70 | 76 | Entry aEntry[N_ENTRY]; |
| 71 | 77 | |
| 78 | +/* | |
| 79 | +** Current help message accumulator | |
| 80 | +*/ | |
| 81 | +char zHelp[MX_HELP]; | |
| 82 | +int nHelp; | |
| 83 | + | |
| 72 | 84 | /* |
| 73 | 85 | ** How many entries are used |
| 74 | 86 | */ |
| 75 | 87 | int nUsed; |
| 76 | 88 | int nFixed; |
| @@ -120,12 +132,24 @@ | ||
| 120 | 132 | |
| 121 | 133 | /* |
| 122 | 134 | ** Scan a line for a function that implements a web page or command. |
| 123 | 135 | */ |
| 124 | 136 | void scan_for_func(char *zLine){ |
| 125 | - int i,j,k; | |
| 137 | + int i,j,k; | |
| 138 | + char *z; | |
| 126 | 139 | if( nUsed<=nFixed ) return; |
| 140 | + if( strncmp(zLine, "**", 2)==0 && isspace(zLine[2]) | |
| 141 | + && strlen(zLine)<sizeof(zHelp)-nHelp-1 && nUsed>nFixed ){ | |
| 142 | + if( zLine[2]=='\n' ){ | |
| 143 | + zHelp[nHelp++] = '\n'; | |
| 144 | + }else{ | |
| 145 | + if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0; | |
| 146 | + strcpy(&zHelp[nHelp], &zLine[3]); | |
| 147 | + nHelp += strlen(&zHelp[nHelp]); | |
| 148 | + } | |
| 149 | + return; | |
| 150 | + } | |
| 127 | 151 | for(i=0; isspace(zLine[i]); i++){} |
| 128 | 152 | if( zLine[i]==0 ) return; |
| 129 | 153 | if( strncmp(&zLine[i],"void",4)!=0 ){ |
| 130 | 154 | if( zLine[i]!='*' ) goto page_skip; |
| 131 | 155 | return; |
| @@ -133,17 +157,28 @@ | ||
| 133 | 157 | i += 4; |
| 134 | 158 | if( !isspace(zLine[i]) ) goto page_skip; |
| 135 | 159 | while( isspace(zLine[i]) ){ i++; } |
| 136 | 160 | for(j=0; isalnum(zLine[i+j]) || zLine[i+j]=='_'; j++){} |
| 137 | 161 | if( j==0 ) goto page_skip; |
| 162 | + for(k=nHelp-1; k>=0 && isspace(zHelp[k]); k--){} | |
| 163 | + nHelp = k+1; | |
| 164 | + zHelp[nHelp] = 0; | |
| 165 | + for(k=0; k<nHelp && isspace(zHelp[k]); k++){} | |
| 166 | + if( k<nHelp ){ | |
| 167 | + z = string_dup(&zHelp[k], nHelp-k); | |
| 168 | + }else{ | |
| 169 | + z = 0; | |
| 170 | + } | |
| 138 | 171 | for(k=nFixed; k<nUsed; k++){ |
| 139 | 172 | aEntry[k].zFunc = string_dup(&zLine[i], j); |
| 173 | + aEntry[k].zHelp = z; | |
| 140 | 174 | } |
| 141 | 175 | i+=j; |
| 142 | 176 | while( isspace(zLine[i]) ){ i++; } |
| 143 | 177 | if( zLine[i]!='(' ) goto page_skip; |
| 144 | 178 | nFixed = nUsed; |
| 179 | + nHelp = 0; | |
| 145 | 180 | return; |
| 146 | 181 | |
| 147 | 182 | page_skip: |
| 148 | 183 | for(i=nFixed; i<nUsed; i++){ |
| 149 | 184 | fprintf(stderr,"%s:%d: skipping page \"%s\"\n", |
| @@ -168,10 +203,11 @@ | ||
| 168 | 203 | /* |
| 169 | 204 | ** Build the binary search table. |
| 170 | 205 | */ |
| 171 | 206 | void build_table(void){ |
| 172 | 207 | int i; |
| 208 | + int nType0; | |
| 173 | 209 | |
| 174 | 210 | qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare); |
| 175 | 211 | for(i=0; i<nFixed; i++){ |
| 176 | 212 | printf("extern void %s(void);\n", aEntry[i].zFunc); |
| 177 | 213 | } |
| @@ -188,18 +224,49 @@ | ||
| 188 | 224 | aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", |
| 189 | 225 | aEntry[i].zFunc |
| 190 | 226 | ); |
| 191 | 227 | } |
| 192 | 228 | printf("};\n"); |
| 229 | + nType0 = i; | |
| 193 | 230 | printf( |
| 194 | 231 | "static const NameMap aCommand[] = {\n" |
| 195 | 232 | ); |
| 196 | - for(; i<nFixed && aEntry[i].eType==1; i++){ | |
| 233 | + for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){ | |
| 197 | 234 | printf(" { \"%s\",%*s %s },\n", |
| 198 | 235 | aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", |
| 199 | 236 | aEntry[i].zFunc |
| 200 | 237 | ); |
| 238 | + } | |
| 239 | + printf("};\n"); | |
| 240 | + for(i=nType0; i<nFixed; i++){ | |
| 241 | + char *z = aEntry[i].zHelp; | |
| 242 | + if( z && z[0] ){ | |
| 243 | + printf("static const char zHelp_%s[] = \n", aEntry[i].zFunc); | |
| 244 | + printf(" \""); | |
| 245 | + while( *z ){ | |
| 246 | + if( *z=='\n' ){ | |
| 247 | + printf("\\n\"\n \""); | |
| 248 | + }else if( *z=='"' ){ | |
| 249 | + printf("\\\""); | |
| 250 | + }else{ | |
| 251 | + putchar(*z); | |
| 252 | + } | |
| 253 | + z++; | |
| 254 | + } | |
| 255 | + printf("\";\n"); | |
| 256 | + aEntry[i].zHelp[0] = 0; | |
| 257 | + } | |
| 258 | + } | |
| 259 | + printf( | |
| 260 | + "static const char * const aCmdHelp[] = {\n" | |
| 261 | + ); | |
| 262 | + for(i=nType0; i<nFixed; i++){ | |
| 263 | + if( aEntry[i].zHelp==0 ){ | |
| 264 | + printf(" 0,\n"); | |
| 265 | + }else{ | |
| 266 | + printf(" zHelp_%s,\n", aEntry[i].zFunc); | |
| 267 | + } | |
| 201 | 268 | } |
| 202 | 269 | printf("};\n"); |
| 203 | 270 | } |
| 204 | 271 | |
| 205 | 272 | /* |
| 206 | 273 |
| --- src/mkindex.c | |
| +++ src/mkindex.c | |
| @@ -55,22 +55,34 @@ | |
| 55 | */ |
| 56 | typedef struct Entry { |
| 57 | int eType; |
| 58 | char *zFunc; |
| 59 | char *zPath; |
| 60 | } Entry; |
| 61 | |
| 62 | /* |
| 63 | ** Maximum number of entries |
| 64 | */ |
| 65 | #define N_ENTRY 500 |
| 66 | |
| 67 | /* |
| 68 | ** Table of entries |
| 69 | */ |
| 70 | Entry aEntry[N_ENTRY]; |
| 71 | |
| 72 | /* |
| 73 | ** How many entries are used |
| 74 | */ |
| 75 | int nUsed; |
| 76 | int nFixed; |
| @@ -120,12 +132,24 @@ | |
| 120 | |
| 121 | /* |
| 122 | ** Scan a line for a function that implements a web page or command. |
| 123 | */ |
| 124 | void scan_for_func(char *zLine){ |
| 125 | int i,j,k; |
| 126 | if( nUsed<=nFixed ) return; |
| 127 | for(i=0; isspace(zLine[i]); i++){} |
| 128 | if( zLine[i]==0 ) return; |
| 129 | if( strncmp(&zLine[i],"void",4)!=0 ){ |
| 130 | if( zLine[i]!='*' ) goto page_skip; |
| 131 | return; |
| @@ -133,17 +157,28 @@ | |
| 133 | i += 4; |
| 134 | if( !isspace(zLine[i]) ) goto page_skip; |
| 135 | while( isspace(zLine[i]) ){ i++; } |
| 136 | for(j=0; isalnum(zLine[i+j]) || zLine[i+j]=='_'; j++){} |
| 137 | if( j==0 ) goto page_skip; |
| 138 | for(k=nFixed; k<nUsed; k++){ |
| 139 | aEntry[k].zFunc = string_dup(&zLine[i], j); |
| 140 | } |
| 141 | i+=j; |
| 142 | while( isspace(zLine[i]) ){ i++; } |
| 143 | if( zLine[i]!='(' ) goto page_skip; |
| 144 | nFixed = nUsed; |
| 145 | return; |
| 146 | |
| 147 | page_skip: |
| 148 | for(i=nFixed; i<nUsed; i++){ |
| 149 | fprintf(stderr,"%s:%d: skipping page \"%s\"\n", |
| @@ -168,10 +203,11 @@ | |
| 168 | /* |
| 169 | ** Build the binary search table. |
| 170 | */ |
| 171 | void build_table(void){ |
| 172 | int i; |
| 173 | |
| 174 | qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare); |
| 175 | for(i=0; i<nFixed; i++){ |
| 176 | printf("extern void %s(void);\n", aEntry[i].zFunc); |
| 177 | } |
| @@ -188,18 +224,49 @@ | |
| 188 | aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", |
| 189 | aEntry[i].zFunc |
| 190 | ); |
| 191 | } |
| 192 | printf("};\n"); |
| 193 | printf( |
| 194 | "static const NameMap aCommand[] = {\n" |
| 195 | ); |
| 196 | for(; i<nFixed && aEntry[i].eType==1; i++){ |
| 197 | printf(" { \"%s\",%*s %s },\n", |
| 198 | aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", |
| 199 | aEntry[i].zFunc |
| 200 | ); |
| 201 | } |
| 202 | printf("};\n"); |
| 203 | } |
| 204 | |
| 205 | /* |
| 206 |
| --- src/mkindex.c | |
| +++ src/mkindex.c | |
| @@ -55,22 +55,34 @@ | |
| 55 | */ |
| 56 | typedef struct Entry { |
| 57 | int eType; |
| 58 | char *zFunc; |
| 59 | char *zPath; |
| 60 | char *zHelp; |
| 61 | } Entry; |
| 62 | |
| 63 | /* |
| 64 | ** Maximum number of entries |
| 65 | */ |
| 66 | #define N_ENTRY 500 |
| 67 | |
| 68 | /* |
| 69 | ** Maximum size of a help message |
| 70 | */ |
| 71 | #define MX_HELP 10000 |
| 72 | |
| 73 | /* |
| 74 | ** Table of entries |
| 75 | */ |
| 76 | Entry aEntry[N_ENTRY]; |
| 77 | |
| 78 | /* |
| 79 | ** Current help message accumulator |
| 80 | */ |
| 81 | char zHelp[MX_HELP]; |
| 82 | int nHelp; |
| 83 | |
| 84 | /* |
| 85 | ** How many entries are used |
| 86 | */ |
| 87 | int nUsed; |
| 88 | int nFixed; |
| @@ -120,12 +132,24 @@ | |
| 132 | |
| 133 | /* |
| 134 | ** Scan a line for a function that implements a web page or command. |
| 135 | */ |
| 136 | void scan_for_func(char *zLine){ |
| 137 | int i,j,k; |
| 138 | char *z; |
| 139 | if( nUsed<=nFixed ) return; |
| 140 | if( strncmp(zLine, "**", 2)==0 && isspace(zLine[2]) |
| 141 | && strlen(zLine)<sizeof(zHelp)-nHelp-1 && nUsed>nFixed ){ |
| 142 | if( zLine[2]=='\n' ){ |
| 143 | zHelp[nHelp++] = '\n'; |
| 144 | }else{ |
| 145 | if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0; |
| 146 | strcpy(&zHelp[nHelp], &zLine[3]); |
| 147 | nHelp += strlen(&zHelp[nHelp]); |
| 148 | } |
| 149 | return; |
| 150 | } |
| 151 | for(i=0; isspace(zLine[i]); i++){} |
| 152 | if( zLine[i]==0 ) return; |
| 153 | if( strncmp(&zLine[i],"void",4)!=0 ){ |
| 154 | if( zLine[i]!='*' ) goto page_skip; |
| 155 | return; |
| @@ -133,17 +157,28 @@ | |
| 157 | i += 4; |
| 158 | if( !isspace(zLine[i]) ) goto page_skip; |
| 159 | while( isspace(zLine[i]) ){ i++; } |
| 160 | for(j=0; isalnum(zLine[i+j]) || zLine[i+j]=='_'; j++){} |
| 161 | if( j==0 ) goto page_skip; |
| 162 | for(k=nHelp-1; k>=0 && isspace(zHelp[k]); k--){} |
| 163 | nHelp = k+1; |
| 164 | zHelp[nHelp] = 0; |
| 165 | for(k=0; k<nHelp && isspace(zHelp[k]); k++){} |
| 166 | if( k<nHelp ){ |
| 167 | z = string_dup(&zHelp[k], nHelp-k); |
| 168 | }else{ |
| 169 | z = 0; |
| 170 | } |
| 171 | for(k=nFixed; k<nUsed; k++){ |
| 172 | aEntry[k].zFunc = string_dup(&zLine[i], j); |
| 173 | aEntry[k].zHelp = z; |
| 174 | } |
| 175 | i+=j; |
| 176 | while( isspace(zLine[i]) ){ i++; } |
| 177 | if( zLine[i]!='(' ) goto page_skip; |
| 178 | nFixed = nUsed; |
| 179 | nHelp = 0; |
| 180 | return; |
| 181 | |
| 182 | page_skip: |
| 183 | for(i=nFixed; i<nUsed; i++){ |
| 184 | fprintf(stderr,"%s:%d: skipping page \"%s\"\n", |
| @@ -168,10 +203,11 @@ | |
| 203 | /* |
| 204 | ** Build the binary search table. |
| 205 | */ |
| 206 | void build_table(void){ |
| 207 | int i; |
| 208 | int nType0; |
| 209 | |
| 210 | qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare); |
| 211 | for(i=0; i<nFixed; i++){ |
| 212 | printf("extern void %s(void);\n", aEntry[i].zFunc); |
| 213 | } |
| @@ -188,18 +224,49 @@ | |
| 224 | aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", |
| 225 | aEntry[i].zFunc |
| 226 | ); |
| 227 | } |
| 228 | printf("};\n"); |
| 229 | nType0 = i; |
| 230 | printf( |
| 231 | "static const NameMap aCommand[] = {\n" |
| 232 | ); |
| 233 | for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){ |
| 234 | printf(" { \"%s\",%*s %s },\n", |
| 235 | aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", |
| 236 | aEntry[i].zFunc |
| 237 | ); |
| 238 | } |
| 239 | printf("};\n"); |
| 240 | for(i=nType0; i<nFixed; i++){ |
| 241 | char *z = aEntry[i].zHelp; |
| 242 | if( z && z[0] ){ |
| 243 | printf("static const char zHelp_%s[] = \n", aEntry[i].zFunc); |
| 244 | printf(" \""); |
| 245 | while( *z ){ |
| 246 | if( *z=='\n' ){ |
| 247 | printf("\\n\"\n \""); |
| 248 | }else if( *z=='"' ){ |
| 249 | printf("\\\""); |
| 250 | }else{ |
| 251 | putchar(*z); |
| 252 | } |
| 253 | z++; |
| 254 | } |
| 255 | printf("\";\n"); |
| 256 | aEntry[i].zHelp[0] = 0; |
| 257 | } |
| 258 | } |
| 259 | printf( |
| 260 | "static const char * const aCmdHelp[] = {\n" |
| 261 | ); |
| 262 | for(i=nType0; i<nFixed; i++){ |
| 263 | if( aEntry[i].zHelp==0 ){ |
| 264 | printf(" 0,\n"); |
| 265 | }else{ |
| 266 | printf(" zHelp_%s,\n", aEntry[i].zFunc); |
| 267 | } |
| 268 | } |
| 269 | printf("};\n"); |
| 270 | } |
| 271 | |
| 272 | /* |
| 273 |