Fossil SCM
Added -- support to wiki create/commit/export. Refactored/simplified how fetching of a dash-as-stdin/stdout argument is done from command-side code.
Commit
dba4fd9b69c5d8c7cb24d6874dcbcc826c5306b69fa303423fe4b3d01b768d52
Parent
78a30d8d7c3d5e2…
3 files changed
+43
-2
+18
-10
+17
-11
+43
-2
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -141,10 +141,13 @@ | ||
| 141 | 141 | }; |
| 142 | 142 | #endif |
| 143 | 143 | |
| 144 | 144 | struct Global { |
| 145 | 145 | int argc; char **argv; /* Command-line arguments to the program */ |
| 146 | + int argDashDashIndex; /* Index of the "--" flag in g.argv, if provided | |
| 147 | + ** (else 0). Not valid until verify_all_options() | |
| 148 | + ** or verify_all_options2() is called. */; | |
| 146 | 149 | char *nameOfExe; /* Full path of executable. */ |
| 147 | 150 | const char *zErrlog; /* Log errors to this file, if not NULL */ |
| 148 | 151 | int isConst; /* True if the output is unchanging & cacheable */ |
| 149 | 152 | const char *zVfsName; /* The VFS to use for database connections */ |
| 150 | 153 | sqlite3 *db; /* The connection to the databases */ |
| @@ -1046,28 +1049,29 @@ | ||
| 1046 | 1049 | ** encountered. |
| 1047 | 1050 | ** |
| 1048 | 1051 | ** Returns false (0) if fAllowDoubleDash is false or if "--" is not |
| 1049 | 1052 | ** encountered. If fAllowDoubleDash is true and "--" is encountered, |
| 1050 | 1053 | ** the argument index (in g.argv) at which "--" was encountered (and |
| 1051 | -** removed) is returned. | |
| 1054 | +** removed) is returned (that value will always be greater than 0). | |
| 1052 | 1055 | ** |
| 1053 | 1056 | ** Sidebar: the question of whether fAllowDoubleDash should be true or |
| 1054 | 1057 | ** false would seem to boil down to: does the calling routine |
| 1055 | 1058 | ** expect/allow arbitrary file/page/branch/whatever name arguments |
| 1056 | 1059 | ** after its required arguments? |
| 1057 | 1060 | */ |
| 1058 | 1061 | static int verify_all_options_impl(int fAllowDoubleDash){ |
| 1059 | 1062 | int i; |
| 1063 | + g.argDashDashIndex = 0; | |
| 1060 | 1064 | for(i=1; i<g.argc; i++){ |
| 1061 | 1065 | const char * arg = g.argv[i]; |
| 1062 | 1066 | if( arg[0]=='-' ){ |
| 1063 | 1067 | if( arg[1]=='-' && arg[2]==0 ){ |
| 1064 | 1068 | if(fAllowDoubleDash){ |
| 1065 | 1069 | /* Remove "--" from the list and assume any following |
| 1066 | 1070 | ** arguments are file names. */ |
| 1067 | 1071 | remove_from_argv(i, 1); |
| 1068 | - return i; | |
| 1072 | + return g.argDashDashIndex = i; | |
| 1069 | 1073 | }else{ |
| 1070 | 1074 | fossil_fatal("The -- flag is not allowed here."); |
| 1071 | 1075 | } |
| 1072 | 1076 | }else if( arg[1]!=0 ){ |
| 1073 | 1077 | fossil_fatal( |
| @@ -1095,10 +1099,47 @@ | ||
| 1095 | 1099 | ** flag and returns true (non-0) if that flag was encountered/consumed. |
| 1096 | 1100 | */ |
| 1097 | 1101 | int verify_all_options2(void){ |
| 1098 | 1102 | return verify_all_options_impl(1); |
| 1099 | 1103 | } |
| 1104 | + | |
| 1105 | +/* | |
| 1106 | +** Expects nArgPos to be a valid index of g.argv. If nArgPos is a | |
| 1107 | +** string with the value "-" and g.argDashDashIndex is greater than 0 | |
| 1108 | +** and <= nArgPos then the value "-" gets transformed to "./-". In all | |
| 1109 | +** other cases, the value of g.argv[nArgPos] is returned as-is. | |
| 1110 | +** | |
| 1111 | +** The intention is that this function be called by commands which | |
| 1112 | +** accept a filename argument for which "-" is interpreted as stdin or | |
| 1113 | +** stdout. If the "--" flag was found BEFORE that filename flag then | |
| 1114 | +** "-" is transformed such that it will be seen as a file named "./-" | |
| 1115 | +** rather than "-" (stdin or stdout, depending on the context). Returns | |
| 1116 | +** a string from g.argv or the static string "./-", so its lifetime is | |
| 1117 | +** effectively that of the app. | |
| 1118 | +*/ | |
| 1119 | +const char * get_dash_filename_arg(int nArgPos){ | |
| 1120 | + const char * zName; | |
| 1121 | + assert(nArgPos < g.argc); | |
| 1122 | + zName = g.argv[nArgPos]; | |
| 1123 | + if(zName!=0 | |
| 1124 | + && g.argDashDashIndex>0 && g.argDashDashIndex<=nArgPos | |
| 1125 | + && fossil_strcmp("-",zName)==0){ | |
| 1126 | + zName = "./-"; | |
| 1127 | + } | |
| 1128 | + return zName; | |
| 1129 | +}; | |
| 1130 | + | |
| 1131 | +/* | |
| 1132 | + ** Only for debugging during "--"-related refactoring. To be deleted | |
| 1133 | + ** before merging with trunk. | |
| 1134 | + */ | |
| 1135 | +void dump_g_argv(){ | |
| 1136 | + int i; | |
| 1137 | + for( i = 0; i < g.argc; ++i ){ | |
| 1138 | + fossil_print("\tg.argv[%d] = %s\n", i, g.argv[i]); | |
| 1139 | + } | |
| 1140 | +} | |
| 1100 | 1141 | |
| 1101 | 1142 | /* |
| 1102 | 1143 | ** This function returns a human readable version string. |
| 1103 | 1144 | */ |
| 1104 | 1145 | const char *get_version(){ |
| 1105 | 1146 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -141,10 +141,13 @@ | |
| 141 | }; |
| 142 | #endif |
| 143 | |
| 144 | struct Global { |
| 145 | int argc; char **argv; /* Command-line arguments to the program */ |
| 146 | char *nameOfExe; /* Full path of executable. */ |
| 147 | const char *zErrlog; /* Log errors to this file, if not NULL */ |
| 148 | int isConst; /* True if the output is unchanging & cacheable */ |
| 149 | const char *zVfsName; /* The VFS to use for database connections */ |
| 150 | sqlite3 *db; /* The connection to the databases */ |
| @@ -1046,28 +1049,29 @@ | |
| 1046 | ** encountered. |
| 1047 | ** |
| 1048 | ** Returns false (0) if fAllowDoubleDash is false or if "--" is not |
| 1049 | ** encountered. If fAllowDoubleDash is true and "--" is encountered, |
| 1050 | ** the argument index (in g.argv) at which "--" was encountered (and |
| 1051 | ** removed) is returned. |
| 1052 | ** |
| 1053 | ** Sidebar: the question of whether fAllowDoubleDash should be true or |
| 1054 | ** false would seem to boil down to: does the calling routine |
| 1055 | ** expect/allow arbitrary file/page/branch/whatever name arguments |
| 1056 | ** after its required arguments? |
| 1057 | */ |
| 1058 | static int verify_all_options_impl(int fAllowDoubleDash){ |
| 1059 | int i; |
| 1060 | for(i=1; i<g.argc; i++){ |
| 1061 | const char * arg = g.argv[i]; |
| 1062 | if( arg[0]=='-' ){ |
| 1063 | if( arg[1]=='-' && arg[2]==0 ){ |
| 1064 | if(fAllowDoubleDash){ |
| 1065 | /* Remove "--" from the list and assume any following |
| 1066 | ** arguments are file names. */ |
| 1067 | remove_from_argv(i, 1); |
| 1068 | return i; |
| 1069 | }else{ |
| 1070 | fossil_fatal("The -- flag is not allowed here."); |
| 1071 | } |
| 1072 | }else if( arg[1]!=0 ){ |
| 1073 | fossil_fatal( |
| @@ -1095,10 +1099,47 @@ | |
| 1095 | ** flag and returns true (non-0) if that flag was encountered/consumed. |
| 1096 | */ |
| 1097 | int verify_all_options2(void){ |
| 1098 | return verify_all_options_impl(1); |
| 1099 | } |
| 1100 | |
| 1101 | /* |
| 1102 | ** This function returns a human readable version string. |
| 1103 | */ |
| 1104 | const char *get_version(){ |
| 1105 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -141,10 +141,13 @@ | |
| 141 | }; |
| 142 | #endif |
| 143 | |
| 144 | struct Global { |
| 145 | int argc; char **argv; /* Command-line arguments to the program */ |
| 146 | int argDashDashIndex; /* Index of the "--" flag in g.argv, if provided |
| 147 | ** (else 0). Not valid until verify_all_options() |
| 148 | ** or verify_all_options2() is called. */; |
| 149 | char *nameOfExe; /* Full path of executable. */ |
| 150 | const char *zErrlog; /* Log errors to this file, if not NULL */ |
| 151 | int isConst; /* True if the output is unchanging & cacheable */ |
| 152 | const char *zVfsName; /* The VFS to use for database connections */ |
| 153 | sqlite3 *db; /* The connection to the databases */ |
| @@ -1046,28 +1049,29 @@ | |
| 1049 | ** encountered. |
| 1050 | ** |
| 1051 | ** Returns false (0) if fAllowDoubleDash is false or if "--" is not |
| 1052 | ** encountered. If fAllowDoubleDash is true and "--" is encountered, |
| 1053 | ** the argument index (in g.argv) at which "--" was encountered (and |
| 1054 | ** removed) is returned (that value will always be greater than 0). |
| 1055 | ** |
| 1056 | ** Sidebar: the question of whether fAllowDoubleDash should be true or |
| 1057 | ** false would seem to boil down to: does the calling routine |
| 1058 | ** expect/allow arbitrary file/page/branch/whatever name arguments |
| 1059 | ** after its required arguments? |
| 1060 | */ |
| 1061 | static int verify_all_options_impl(int fAllowDoubleDash){ |
| 1062 | int i; |
| 1063 | g.argDashDashIndex = 0; |
| 1064 | for(i=1; i<g.argc; i++){ |
| 1065 | const char * arg = g.argv[i]; |
| 1066 | if( arg[0]=='-' ){ |
| 1067 | if( arg[1]=='-' && arg[2]==0 ){ |
| 1068 | if(fAllowDoubleDash){ |
| 1069 | /* Remove "--" from the list and assume any following |
| 1070 | ** arguments are file names. */ |
| 1071 | remove_from_argv(i, 1); |
| 1072 | return g.argDashDashIndex = i; |
| 1073 | }else{ |
| 1074 | fossil_fatal("The -- flag is not allowed here."); |
| 1075 | } |
| 1076 | }else if( arg[1]!=0 ){ |
| 1077 | fossil_fatal( |
| @@ -1095,10 +1099,47 @@ | |
| 1099 | ** flag and returns true (non-0) if that flag was encountered/consumed. |
| 1100 | */ |
| 1101 | int verify_all_options2(void){ |
| 1102 | return verify_all_options_impl(1); |
| 1103 | } |
| 1104 | |
| 1105 | /* |
| 1106 | ** Expects nArgPos to be a valid index of g.argv. If nArgPos is a |
| 1107 | ** string with the value "-" and g.argDashDashIndex is greater than 0 |
| 1108 | ** and <= nArgPos then the value "-" gets transformed to "./-". In all |
| 1109 | ** other cases, the value of g.argv[nArgPos] is returned as-is. |
| 1110 | ** |
| 1111 | ** The intention is that this function be called by commands which |
| 1112 | ** accept a filename argument for which "-" is interpreted as stdin or |
| 1113 | ** stdout. If the "--" flag was found BEFORE that filename flag then |
| 1114 | ** "-" is transformed such that it will be seen as a file named "./-" |
| 1115 | ** rather than "-" (stdin or stdout, depending on the context). Returns |
| 1116 | ** a string from g.argv or the static string "./-", so its lifetime is |
| 1117 | ** effectively that of the app. |
| 1118 | */ |
| 1119 | const char * get_dash_filename_arg(int nArgPos){ |
| 1120 | const char * zName; |
| 1121 | assert(nArgPos < g.argc); |
| 1122 | zName = g.argv[nArgPos]; |
| 1123 | if(zName!=0 |
| 1124 | && g.argDashDashIndex>0 && g.argDashDashIndex<=nArgPos |
| 1125 | && fossil_strcmp("-",zName)==0){ |
| 1126 | zName = "./-"; |
| 1127 | } |
| 1128 | return zName; |
| 1129 | }; |
| 1130 | |
| 1131 | /* |
| 1132 | ** Only for debugging during "--"-related refactoring. To be deleted |
| 1133 | ** before merging with trunk. |
| 1134 | */ |
| 1135 | void dump_g_argv(){ |
| 1136 | int i; |
| 1137 | for( i = 0; i < g.argc; ++i ){ |
| 1138 | fossil_print("\tg.argv[%d] = %s\n", i, g.argv[i]); |
| 1139 | } |
| 1140 | } |
| 1141 | |
| 1142 | /* |
| 1143 | ** This function returns a human readable version string. |
| 1144 | */ |
| 1145 | const char *get_version(){ |
| 1146 |
+18
-10
| --- src/unversioned.c | ||
| +++ src/unversioned.c | ||
| @@ -296,14 +296,13 @@ | ||
| 296 | 296 | const char *zIn; |
| 297 | 297 | const char *zAs; |
| 298 | 298 | const char *zFileArg; |
| 299 | 299 | Blob file; |
| 300 | 300 | int i; |
| 301 | - int fDoubleDash; /* True if "--" flag is provided */ | |
| 302 | 301 | zAs = find_option("as",0,1); |
| 303 | - fDoubleDash = verify_all_options2(); | |
| 304 | - if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE"); | |
| 302 | + verify_all_options2(); | |
| 303 | + if( zAs && g.argc!=4 ) usage("add --as UVFILE [--] DISKFILE"); | |
| 305 | 304 | db_begin_transaction(); |
| 306 | 305 | content_rcvid_init("#!fossil unversioned add"); |
| 307 | 306 | for(i=3; i<g.argc; i++){ |
| 308 | 307 | zIn = zAs ? zAs : g.argv[i]; |
| 309 | 308 | if( zIn[0]==0 ){ |
| @@ -317,15 +316,11 @@ | ||
| 317 | 316 | } |
| 318 | 317 | if( zError ){ |
| 319 | 318 | fossil_fatal("unversioned filenames may not %s: %Q", zError, zIn); |
| 320 | 319 | } |
| 321 | 320 | blob_init(&file,0,0); |
| 322 | - zFileArg = g.argv[i]; | |
| 323 | - if(fDoubleDash>0 && fDoubleDash<=i | |
| 324 | - && fossil_strcmp("-",zFileArg)==0){ | |
| 325 | - zFileArg = "./-" /* do not treat "-" as stdin! */; | |
| 326 | - } | |
| 321 | + zFileArg = get_dash_filename_arg(i); | |
| 327 | 322 | blob_read_from_file(&file, zFileArg, ExtFILE); |
| 328 | 323 | unversioned_write(zIn, &file, mtime); |
| 329 | 324 | blob_reset(&file); |
| 330 | 325 | } |
| 331 | 326 | db_end_transaction(0); |
| @@ -382,16 +377,29 @@ | ||
| 382 | 377 | unversioned_write(zUVFile, &content, mtime); |
| 383 | 378 | db_end_transaction(0); |
| 384 | 379 | blob_reset(&content); |
| 385 | 380 | }else if( memcmp(zCmd, "export", nCmd)==0 ){ |
| 386 | 381 | Blob content; |
| 382 | + const char * zOutfile; | |
| 387 | 383 | verify_all_options2(); |
| 388 | - if( g.argc!=5 ) usage("export UVFILE OUTPUT"); | |
| 384 | + if( g.argc!=5 ) usage("export [--] UVFILE OUTPUT"); | |
| 389 | 385 | if( unversioned_content(g.argv[3], &content) ){ |
| 390 | 386 | fossil_fatal("no such uv-file: %Q", g.argv[3]); |
| 391 | 387 | } |
| 392 | - blob_write_to_file(&content, g.argv[4]); | |
| 388 | + /* | |
| 389 | + ** Pathological(?) corner case: | |
| 390 | + ** | |
| 391 | + ** export -- --UVFILE - | |
| 392 | + ** | |
| 393 | + ** We have no way of applying -- to just the UVFILE name but not | |
| 394 | + ** the output file name, so the above would output the uv file | |
| 395 | + ** literally named --UVFILE to a file literally named -. The only | |
| 396 | + ** alternative is that we never apply -- to the output file name, | |
| 397 | + ** which seems likely to cause yet more confusion. | |
| 398 | + */ | |
| 399 | + zOutfile = get_dash_filename_arg(4); | |
| 400 | + blob_write_to_file(&content, zOutfile); | |
| 393 | 401 | blob_reset(&content); |
| 394 | 402 | }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ |
| 395 | 403 | /* Show the hash value used during uv sync */ |
| 396 | 404 | int debugFlag = find_option("debug",0,0)!=0; |
| 397 | 405 | fossil_print("%s\n", unversioned_content_hash(debugFlag)); |
| 398 | 406 |
| --- src/unversioned.c | |
| +++ src/unversioned.c | |
| @@ -296,14 +296,13 @@ | |
| 296 | const char *zIn; |
| 297 | const char *zAs; |
| 298 | const char *zFileArg; |
| 299 | Blob file; |
| 300 | int i; |
| 301 | int fDoubleDash; /* True if "--" flag is provided */ |
| 302 | zAs = find_option("as",0,1); |
| 303 | fDoubleDash = verify_all_options2(); |
| 304 | if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE"); |
| 305 | db_begin_transaction(); |
| 306 | content_rcvid_init("#!fossil unversioned add"); |
| 307 | for(i=3; i<g.argc; i++){ |
| 308 | zIn = zAs ? zAs : g.argv[i]; |
| 309 | if( zIn[0]==0 ){ |
| @@ -317,15 +316,11 @@ | |
| 317 | } |
| 318 | if( zError ){ |
| 319 | fossil_fatal("unversioned filenames may not %s: %Q", zError, zIn); |
| 320 | } |
| 321 | blob_init(&file,0,0); |
| 322 | zFileArg = g.argv[i]; |
| 323 | if(fDoubleDash>0 && fDoubleDash<=i |
| 324 | && fossil_strcmp("-",zFileArg)==0){ |
| 325 | zFileArg = "./-" /* do not treat "-" as stdin! */; |
| 326 | } |
| 327 | blob_read_from_file(&file, zFileArg, ExtFILE); |
| 328 | unversioned_write(zIn, &file, mtime); |
| 329 | blob_reset(&file); |
| 330 | } |
| 331 | db_end_transaction(0); |
| @@ -382,16 +377,29 @@ | |
| 382 | unversioned_write(zUVFile, &content, mtime); |
| 383 | db_end_transaction(0); |
| 384 | blob_reset(&content); |
| 385 | }else if( memcmp(zCmd, "export", nCmd)==0 ){ |
| 386 | Blob content; |
| 387 | verify_all_options2(); |
| 388 | if( g.argc!=5 ) usage("export UVFILE OUTPUT"); |
| 389 | if( unversioned_content(g.argv[3], &content) ){ |
| 390 | fossil_fatal("no such uv-file: %Q", g.argv[3]); |
| 391 | } |
| 392 | blob_write_to_file(&content, g.argv[4]); |
| 393 | blob_reset(&content); |
| 394 | }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ |
| 395 | /* Show the hash value used during uv sync */ |
| 396 | int debugFlag = find_option("debug",0,0)!=0; |
| 397 | fossil_print("%s\n", unversioned_content_hash(debugFlag)); |
| 398 |
| --- src/unversioned.c | |
| +++ src/unversioned.c | |
| @@ -296,14 +296,13 @@ | |
| 296 | const char *zIn; |
| 297 | const char *zAs; |
| 298 | const char *zFileArg; |
| 299 | Blob file; |
| 300 | int i; |
| 301 | zAs = find_option("as",0,1); |
| 302 | verify_all_options2(); |
| 303 | if( zAs && g.argc!=4 ) usage("add --as UVFILE [--] DISKFILE"); |
| 304 | db_begin_transaction(); |
| 305 | content_rcvid_init("#!fossil unversioned add"); |
| 306 | for(i=3; i<g.argc; i++){ |
| 307 | zIn = zAs ? zAs : g.argv[i]; |
| 308 | if( zIn[0]==0 ){ |
| @@ -317,15 +316,11 @@ | |
| 316 | } |
| 317 | if( zError ){ |
| 318 | fossil_fatal("unversioned filenames may not %s: %Q", zError, zIn); |
| 319 | } |
| 320 | blob_init(&file,0,0); |
| 321 | zFileArg = get_dash_filename_arg(i); |
| 322 | blob_read_from_file(&file, zFileArg, ExtFILE); |
| 323 | unversioned_write(zIn, &file, mtime); |
| 324 | blob_reset(&file); |
| 325 | } |
| 326 | db_end_transaction(0); |
| @@ -382,16 +377,29 @@ | |
| 377 | unversioned_write(zUVFile, &content, mtime); |
| 378 | db_end_transaction(0); |
| 379 | blob_reset(&content); |
| 380 | }else if( memcmp(zCmd, "export", nCmd)==0 ){ |
| 381 | Blob content; |
| 382 | const char * zOutfile; |
| 383 | verify_all_options2(); |
| 384 | if( g.argc!=5 ) usage("export [--] UVFILE OUTPUT"); |
| 385 | if( unversioned_content(g.argv[3], &content) ){ |
| 386 | fossil_fatal("no such uv-file: %Q", g.argv[3]); |
| 387 | } |
| 388 | /* |
| 389 | ** Pathological(?) corner case: |
| 390 | ** |
| 391 | ** export -- --UVFILE - |
| 392 | ** |
| 393 | ** We have no way of applying -- to just the UVFILE name but not |
| 394 | ** the output file name, so the above would output the uv file |
| 395 | ** literally named --UVFILE to a file literally named -. The only |
| 396 | ** alternative is that we never apply -- to the output file name, |
| 397 | ** which seems likely to cause yet more confusion. |
| 398 | */ |
| 399 | zOutfile = get_dash_filename_arg(4); |
| 400 | blob_write_to_file(&content, zOutfile); |
| 401 | blob_reset(&content); |
| 402 | }else if( memcmp(zCmd, "hash", nCmd)==0 ){ /* undocumented */ |
| 403 | /* Show the hash value used during uv sync */ |
| 404 | int debugFlag = find_option("debug",0,0)!=0; |
| 405 | fossil_print("%s\n", unversioned_content_hash(debugFlag)); |
| 406 |
+17
-11
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -1364,12 +1364,12 @@ | ||
| 1364 | 1364 | ** |
| 1365 | 1365 | ** Usage: %fossil wiki (export|create|commit|list) WikiName |
| 1366 | 1366 | ** |
| 1367 | 1367 | ** Run various subcommands to work with wiki entries or tech notes. |
| 1368 | 1368 | ** |
| 1369 | -** %fossil wiki export PAGENAME ?FILE? | |
| 1370 | -** %fossil wiki export ?FILE? -t|--technote DATETIME|TECHNOTE-ID | |
| 1369 | +** %fossil wiki export PAGENAME [--] ?FILE? | |
| 1370 | +** %fossil wiki export -t|--technote DATETIME|TECHNOTE-ID [--] ?FILE? | |
| 1371 | 1371 | ** |
| 1372 | 1372 | ** Sends the latest version of either a wiki page or of a tech note |
| 1373 | 1373 | ** to the given file or standard output. |
| 1374 | 1374 | ** If PAGENAME is provided, the wiki page will be output. For |
| 1375 | 1375 | ** a tech note either DATETIME or TECHNOTE-ID must be specified. If |
| @@ -1425,10 +1425,15 @@ | ||
| 1425 | 1425 | ** year-month-day form, it may be truncated, the "T" may be replaced by |
| 1426 | 1426 | ** a space, and it may also name a timezone offset from UTC as "-HH:MM" |
| 1427 | 1427 | ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" |
| 1428 | 1428 | ** means UTC. |
| 1429 | 1429 | ** |
| 1430 | +** Options: | |
| 1431 | +** -- For commands which support this, it means to treat | |
| 1432 | +** all subsequent arguments as file names even if they | |
| 1433 | +** start with a "-". | |
| 1434 | +** | |
| 1430 | 1435 | */ |
| 1431 | 1436 | void wiki_cmd(void){ |
| 1432 | 1437 | int n; |
| 1433 | 1438 | db_find_and_open_repository(0, 0); |
| 1434 | 1439 | if( g.argc<3 ){ |
| @@ -1436,25 +1441,24 @@ | ||
| 1436 | 1441 | } |
| 1437 | 1442 | n = strlen(g.argv[2]); |
| 1438 | 1443 | if( n==0 ){ |
| 1439 | 1444 | goto wiki_cmd_usage; |
| 1440 | 1445 | } |
| 1441 | - | |
| 1442 | 1446 | if( strncmp(g.argv[2],"export",n)==0 ){ |
| 1443 | 1447 | const char *zPageName; /* Name of the wiki page to export */ |
| 1444 | 1448 | const char *zFile; /* Name of the output file (0=stdout) */ |
| 1445 | 1449 | const char *zETime; /* The name of the technote to export */ |
| 1446 | 1450 | int rid; /* Artifact ID of the wiki page */ |
| 1447 | 1451 | int i; /* Loop counter */ |
| 1448 | 1452 | char *zBody = 0; /* Wiki page content */ |
| 1449 | 1453 | Blob body; /* Wiki page content */ |
| 1450 | 1454 | Manifest *pWiki = 0; /* Parsed wiki page content */ |
| 1451 | - | |
| 1452 | 1455 | zETime = find_option("technote","t",1); |
| 1456 | + verify_all_options2(); | |
| 1453 | 1457 | if( !zETime ){ |
| 1454 | 1458 | if( (g.argc!=4) && (g.argc!=5) ){ |
| 1455 | - usage("export PAGENAME ?FILE?"); | |
| 1459 | + usage("export PAGENAME [--] ?FILE?"); | |
| 1456 | 1460 | } |
| 1457 | 1461 | zPageName = g.argv[3]; |
| 1458 | 1462 | rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" |
| 1459 | 1463 | " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" |
| 1460 | 1464 | " ORDER BY x.mtime DESC LIMIT 1", |
| @@ -1464,14 +1468,14 @@ | ||
| 1464 | 1468 | zBody = pWiki->zWiki; |
| 1465 | 1469 | } |
| 1466 | 1470 | if( zBody==0 ){ |
| 1467 | 1471 | fossil_fatal("wiki page [%s] not found",zPageName); |
| 1468 | 1472 | } |
| 1469 | - zFile = (g.argc==4) ? "-" : g.argv[4]; | |
| 1473 | + zFile = g.argc==4 ? "-" : get_dash_filename_arg(4); | |
| 1470 | 1474 | }else{ |
| 1471 | 1475 | if( (g.argc!=3) && (g.argc!=4) ){ |
| 1472 | - usage("export ?FILE? --technote DATETIME|TECHNOTE-ID"); | |
| 1476 | + usage("export --technote DATETIME|TECHNOTE-ID [--] ?FILE?"); | |
| 1473 | 1477 | } |
| 1474 | 1478 | rid = wiki_technote_to_rid(zETime); |
| 1475 | 1479 | if ( rid==-1 ){ |
| 1476 | 1480 | fossil_fatal("ambiguous tech note id: %s", zETime); |
| 1477 | 1481 | } |
| @@ -1479,11 +1483,11 @@ | ||
| 1479 | 1483 | zBody = pWiki->zWiki; |
| 1480 | 1484 | } |
| 1481 | 1485 | if( zBody==0 ){ |
| 1482 | 1486 | fossil_fatal("technote [%s] not found",zETime); |
| 1483 | 1487 | } |
| 1484 | - zFile = (g.argc==3) ? "-" : g.argv[3]; | |
| 1488 | + zFile = g.argc==3 ? "-" : get_dash_filename_arg(3); | |
| 1485 | 1489 | } |
| 1486 | 1490 | for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){} |
| 1487 | 1491 | zBody[i] = 0; |
| 1488 | 1492 | blob_init(&body, zBody, -1); |
| 1489 | 1493 | blob_append(&body, "\n", 1); |
| @@ -1499,20 +1503,22 @@ | ||
| 1499 | 1503 | Manifest *pWiki = 0; /* Parsed wiki page content */ |
| 1500 | 1504 | const char *zMimeType = find_option("mimetype", "M", 1); |
| 1501 | 1505 | const char *zETime = find_option("technote", "t", 1); |
| 1502 | 1506 | const char *zTags = find_option("technote-tags", NULL, 1); |
| 1503 | 1507 | const char *zClr = find_option("technote-bgcolor", NULL, 1); |
| 1508 | + verify_all_options2(); | |
| 1504 | 1509 | if( g.argc!=4 && g.argc!=5 ){ |
| 1505 | - usage("commit|create PAGENAME ?FILE? [--mimetype TEXT-FORMAT]" | |
| 1510 | + usage("commit|create PAGENAME [--mimetype TEXT-FORMAT]" | |
| 1506 | 1511 | " [--technote DATETIME] [--technote-tags TAGS]" |
| 1507 | - " [--technote-bgcolor COLOR]"); | |
| 1512 | + " [--technote-bgcolor COLOR] [--] ?FILE?"); | |
| 1508 | 1513 | } |
| 1509 | 1514 | zPageName = g.argv[3]; |
| 1510 | 1515 | if( g.argc==4 ){ |
| 1511 | 1516 | blob_read_from_channel(&content, stdin, -1); |
| 1512 | 1517 | }else{ |
| 1513 | - blob_read_from_file(&content, g.argv[4], ExtFILE); | |
| 1518 | + const char * zFilename = get_dash_filename_arg(4); | |
| 1519 | + blob_read_from_file(&content, zFilename, ExtFILE); | |
| 1514 | 1520 | } |
| 1515 | 1521 | if( !zMimeType || !*zMimeType ){ |
| 1516 | 1522 | /* Try to deduce the mime type based on the prior version. */ |
| 1517 | 1523 | if ( !zETime ){ |
| 1518 | 1524 | rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" |
| 1519 | 1525 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1364,12 +1364,12 @@ | |
| 1364 | ** |
| 1365 | ** Usage: %fossil wiki (export|create|commit|list) WikiName |
| 1366 | ** |
| 1367 | ** Run various subcommands to work with wiki entries or tech notes. |
| 1368 | ** |
| 1369 | ** %fossil wiki export PAGENAME ?FILE? |
| 1370 | ** %fossil wiki export ?FILE? -t|--technote DATETIME|TECHNOTE-ID |
| 1371 | ** |
| 1372 | ** Sends the latest version of either a wiki page or of a tech note |
| 1373 | ** to the given file or standard output. |
| 1374 | ** If PAGENAME is provided, the wiki page will be output. For |
| 1375 | ** a tech note either DATETIME or TECHNOTE-ID must be specified. If |
| @@ -1425,10 +1425,15 @@ | |
| 1425 | ** year-month-day form, it may be truncated, the "T" may be replaced by |
| 1426 | ** a space, and it may also name a timezone offset from UTC as "-HH:MM" |
| 1427 | ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" |
| 1428 | ** means UTC. |
| 1429 | ** |
| 1430 | */ |
| 1431 | void wiki_cmd(void){ |
| 1432 | int n; |
| 1433 | db_find_and_open_repository(0, 0); |
| 1434 | if( g.argc<3 ){ |
| @@ -1436,25 +1441,24 @@ | |
| 1436 | } |
| 1437 | n = strlen(g.argv[2]); |
| 1438 | if( n==0 ){ |
| 1439 | goto wiki_cmd_usage; |
| 1440 | } |
| 1441 | |
| 1442 | if( strncmp(g.argv[2],"export",n)==0 ){ |
| 1443 | const char *zPageName; /* Name of the wiki page to export */ |
| 1444 | const char *zFile; /* Name of the output file (0=stdout) */ |
| 1445 | const char *zETime; /* The name of the technote to export */ |
| 1446 | int rid; /* Artifact ID of the wiki page */ |
| 1447 | int i; /* Loop counter */ |
| 1448 | char *zBody = 0; /* Wiki page content */ |
| 1449 | Blob body; /* Wiki page content */ |
| 1450 | Manifest *pWiki = 0; /* Parsed wiki page content */ |
| 1451 | |
| 1452 | zETime = find_option("technote","t",1); |
| 1453 | if( !zETime ){ |
| 1454 | if( (g.argc!=4) && (g.argc!=5) ){ |
| 1455 | usage("export PAGENAME ?FILE?"); |
| 1456 | } |
| 1457 | zPageName = g.argv[3]; |
| 1458 | rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" |
| 1459 | " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" |
| 1460 | " ORDER BY x.mtime DESC LIMIT 1", |
| @@ -1464,14 +1468,14 @@ | |
| 1464 | zBody = pWiki->zWiki; |
| 1465 | } |
| 1466 | if( zBody==0 ){ |
| 1467 | fossil_fatal("wiki page [%s] not found",zPageName); |
| 1468 | } |
| 1469 | zFile = (g.argc==4) ? "-" : g.argv[4]; |
| 1470 | }else{ |
| 1471 | if( (g.argc!=3) && (g.argc!=4) ){ |
| 1472 | usage("export ?FILE? --technote DATETIME|TECHNOTE-ID"); |
| 1473 | } |
| 1474 | rid = wiki_technote_to_rid(zETime); |
| 1475 | if ( rid==-1 ){ |
| 1476 | fossil_fatal("ambiguous tech note id: %s", zETime); |
| 1477 | } |
| @@ -1479,11 +1483,11 @@ | |
| 1479 | zBody = pWiki->zWiki; |
| 1480 | } |
| 1481 | if( zBody==0 ){ |
| 1482 | fossil_fatal("technote [%s] not found",zETime); |
| 1483 | } |
| 1484 | zFile = (g.argc==3) ? "-" : g.argv[3]; |
| 1485 | } |
| 1486 | for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){} |
| 1487 | zBody[i] = 0; |
| 1488 | blob_init(&body, zBody, -1); |
| 1489 | blob_append(&body, "\n", 1); |
| @@ -1499,20 +1503,22 @@ | |
| 1499 | Manifest *pWiki = 0; /* Parsed wiki page content */ |
| 1500 | const char *zMimeType = find_option("mimetype", "M", 1); |
| 1501 | const char *zETime = find_option("technote", "t", 1); |
| 1502 | const char *zTags = find_option("technote-tags", NULL, 1); |
| 1503 | const char *zClr = find_option("technote-bgcolor", NULL, 1); |
| 1504 | if( g.argc!=4 && g.argc!=5 ){ |
| 1505 | usage("commit|create PAGENAME ?FILE? [--mimetype TEXT-FORMAT]" |
| 1506 | " [--technote DATETIME] [--technote-tags TAGS]" |
| 1507 | " [--technote-bgcolor COLOR]"); |
| 1508 | } |
| 1509 | zPageName = g.argv[3]; |
| 1510 | if( g.argc==4 ){ |
| 1511 | blob_read_from_channel(&content, stdin, -1); |
| 1512 | }else{ |
| 1513 | blob_read_from_file(&content, g.argv[4], ExtFILE); |
| 1514 | } |
| 1515 | if( !zMimeType || !*zMimeType ){ |
| 1516 | /* Try to deduce the mime type based on the prior version. */ |
| 1517 | if ( !zETime ){ |
| 1518 | rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" |
| 1519 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1364,12 +1364,12 @@ | |
| 1364 | ** |
| 1365 | ** Usage: %fossil wiki (export|create|commit|list) WikiName |
| 1366 | ** |
| 1367 | ** Run various subcommands to work with wiki entries or tech notes. |
| 1368 | ** |
| 1369 | ** %fossil wiki export PAGENAME [--] ?FILE? |
| 1370 | ** %fossil wiki export -t|--technote DATETIME|TECHNOTE-ID [--] ?FILE? |
| 1371 | ** |
| 1372 | ** Sends the latest version of either a wiki page or of a tech note |
| 1373 | ** to the given file or standard output. |
| 1374 | ** If PAGENAME is provided, the wiki page will be output. For |
| 1375 | ** a tech note either DATETIME or TECHNOTE-ID must be specified. If |
| @@ -1425,10 +1425,15 @@ | |
| 1425 | ** year-month-day form, it may be truncated, the "T" may be replaced by |
| 1426 | ** a space, and it may also name a timezone offset from UTC as "-HH:MM" |
| 1427 | ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" |
| 1428 | ** means UTC. |
| 1429 | ** |
| 1430 | ** Options: |
| 1431 | ** -- For commands which support this, it means to treat |
| 1432 | ** all subsequent arguments as file names even if they |
| 1433 | ** start with a "-". |
| 1434 | ** |
| 1435 | */ |
| 1436 | void wiki_cmd(void){ |
| 1437 | int n; |
| 1438 | db_find_and_open_repository(0, 0); |
| 1439 | if( g.argc<3 ){ |
| @@ -1436,25 +1441,24 @@ | |
| 1441 | } |
| 1442 | n = strlen(g.argv[2]); |
| 1443 | if( n==0 ){ |
| 1444 | goto wiki_cmd_usage; |
| 1445 | } |
| 1446 | if( strncmp(g.argv[2],"export",n)==0 ){ |
| 1447 | const char *zPageName; /* Name of the wiki page to export */ |
| 1448 | const char *zFile; /* Name of the output file (0=stdout) */ |
| 1449 | const char *zETime; /* The name of the technote to export */ |
| 1450 | int rid; /* Artifact ID of the wiki page */ |
| 1451 | int i; /* Loop counter */ |
| 1452 | char *zBody = 0; /* Wiki page content */ |
| 1453 | Blob body; /* Wiki page content */ |
| 1454 | Manifest *pWiki = 0; /* Parsed wiki page content */ |
| 1455 | zETime = find_option("technote","t",1); |
| 1456 | verify_all_options2(); |
| 1457 | if( !zETime ){ |
| 1458 | if( (g.argc!=4) && (g.argc!=5) ){ |
| 1459 | usage("export PAGENAME [--] ?FILE?"); |
| 1460 | } |
| 1461 | zPageName = g.argv[3]; |
| 1462 | rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" |
| 1463 | " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" |
| 1464 | " ORDER BY x.mtime DESC LIMIT 1", |
| @@ -1464,14 +1468,14 @@ | |
| 1468 | zBody = pWiki->zWiki; |
| 1469 | } |
| 1470 | if( zBody==0 ){ |
| 1471 | fossil_fatal("wiki page [%s] not found",zPageName); |
| 1472 | } |
| 1473 | zFile = g.argc==4 ? "-" : get_dash_filename_arg(4); |
| 1474 | }else{ |
| 1475 | if( (g.argc!=3) && (g.argc!=4) ){ |
| 1476 | usage("export --technote DATETIME|TECHNOTE-ID [--] ?FILE?"); |
| 1477 | } |
| 1478 | rid = wiki_technote_to_rid(zETime); |
| 1479 | if ( rid==-1 ){ |
| 1480 | fossil_fatal("ambiguous tech note id: %s", zETime); |
| 1481 | } |
| @@ -1479,11 +1483,11 @@ | |
| 1483 | zBody = pWiki->zWiki; |
| 1484 | } |
| 1485 | if( zBody==0 ){ |
| 1486 | fossil_fatal("technote [%s] not found",zETime); |
| 1487 | } |
| 1488 | zFile = g.argc==3 ? "-" : get_dash_filename_arg(3); |
| 1489 | } |
| 1490 | for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){} |
| 1491 | zBody[i] = 0; |
| 1492 | blob_init(&body, zBody, -1); |
| 1493 | blob_append(&body, "\n", 1); |
| @@ -1499,20 +1503,22 @@ | |
| 1503 | Manifest *pWiki = 0; /* Parsed wiki page content */ |
| 1504 | const char *zMimeType = find_option("mimetype", "M", 1); |
| 1505 | const char *zETime = find_option("technote", "t", 1); |
| 1506 | const char *zTags = find_option("technote-tags", NULL, 1); |
| 1507 | const char *zClr = find_option("technote-bgcolor", NULL, 1); |
| 1508 | verify_all_options2(); |
| 1509 | if( g.argc!=4 && g.argc!=5 ){ |
| 1510 | usage("commit|create PAGENAME [--mimetype TEXT-FORMAT]" |
| 1511 | " [--technote DATETIME] [--technote-tags TAGS]" |
| 1512 | " [--technote-bgcolor COLOR] [--] ?FILE?"); |
| 1513 | } |
| 1514 | zPageName = g.argv[3]; |
| 1515 | if( g.argc==4 ){ |
| 1516 | blob_read_from_channel(&content, stdin, -1); |
| 1517 | }else{ |
| 1518 | const char * zFilename = get_dash_filename_arg(4); |
| 1519 | blob_read_from_file(&content, zFilename, ExtFILE); |
| 1520 | } |
| 1521 | if( !zMimeType || !*zMimeType ){ |
| 1522 | /* Try to deduce the mime type based on the prior version. */ |
| 1523 | if ( !zETime ){ |
| 1524 | rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" |
| 1525 |