Fossil SCM
merge trunk
Commit
6a8ddc43fccaa6e7c0e6d24ee99a828652ff526c
Parent
2e7639302184314…
7 files changed
+5
-1
+3
-3
+3
-3
+1
-1
+35
-5
+3
-3
+32
M
src/db.c
+5
-1
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -711,12 +711,16 @@ | ||
| 711 | 711 | */ |
| 712 | 712 | LOCAL sqlite3 *db_open(const char *zDbName){ |
| 713 | 713 | int rc; |
| 714 | 714 | sqlite3 *db; |
| 715 | 715 | |
| 716 | -#if defined(__CYGWIN__) | |
| 716 | +#if defined(__CYGWIN__) || defined(_WIN32) | |
| 717 | 717 | zDbName = fossil_utf8_to_filename(zDbName); |
| 718 | +#ifdef _WIN32 | |
| 719 | + /* Convert back to utf-8. TODO: SQLite should handle this */ | |
| 720 | + zDbName = fossil_filename_to_utf8(zDbName); | |
| 721 | +#endif | |
| 718 | 722 | #endif |
| 719 | 723 | if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName); |
| 720 | 724 | rc = sqlite3_open_v2( |
| 721 | 725 | zDbName, &db, |
| 722 | 726 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
| 723 | 727 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -711,12 +711,16 @@ | |
| 711 | */ |
| 712 | LOCAL sqlite3 *db_open(const char *zDbName){ |
| 713 | int rc; |
| 714 | sqlite3 *db; |
| 715 | |
| 716 | #if defined(__CYGWIN__) |
| 717 | zDbName = fossil_utf8_to_filename(zDbName); |
| 718 | #endif |
| 719 | if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName); |
| 720 | rc = sqlite3_open_v2( |
| 721 | zDbName, &db, |
| 722 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
| 723 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -711,12 +711,16 @@ | |
| 711 | */ |
| 712 | LOCAL sqlite3 *db_open(const char *zDbName){ |
| 713 | int rc; |
| 714 | sqlite3 *db; |
| 715 | |
| 716 | #if defined(__CYGWIN__) || defined(_WIN32) |
| 717 | zDbName = fossil_utf8_to_filename(zDbName); |
| 718 | #ifdef _WIN32 |
| 719 | /* Convert back to utf-8. TODO: SQLite should handle this */ |
| 720 | zDbName = fossil_filename_to_utf8(zDbName); |
| 721 | #endif |
| 722 | #endif |
| 723 | if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName); |
| 724 | rc = sqlite3_open_v2( |
| 725 | zDbName, &db, |
| 726 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
| 727 |
+3
-3
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -2214,18 +2214,18 @@ | ||
| 2214 | 2214 | ** clrifsame: clear the value if same as default. |
| 2215 | 2215 | ** isempty: returns true if string has no non-whitespace characters. |
| 2216 | 2216 | */ |
| 2217 | 2217 | @ <script> |
| 2218 | 2218 | @ function chgcbn(checked, branch){ |
| 2219 | - @ val = gebi('brname').value; | |
| 2219 | + @ val = gebi('brname').value.trim(); | |
| 2220 | 2220 | @ if( !val || !checked ) val = branch; |
| 2221 | 2221 | @ gebi('hbranch').textContent = val; |
| 2222 | 2222 | @ cidbrid = document.getElementById('cbranch'); |
| 2223 | 2223 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2224 | 2224 | @ } |
| 2225 | 2225 | @ function chgbn(val, branch){ |
| 2226 | - @ if( isempty(val) ) val = branch; | |
| 2226 | + @ if( !val ) val = branch; | |
| 2227 | 2227 | @ gebi('newbr').checked = (val!=branch); |
| 2228 | 2228 | @ gebi('hbranch').textContent = val; |
| 2229 | 2229 | @ cidbrid = document.getElementById('cbranch'); |
| 2230 | 2230 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2231 | 2231 | @ } |
| @@ -2365,11 +2365,11 @@ | ||
| 2365 | 2365 | @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) |
| 2366 | 2366 | @ onchange="chgcbn(this.checked,'%h(zBranchName)')" /> |
| 2367 | 2367 | @ Make this check-in the start of a new branch named:</label> |
| 2368 | 2368 | @ <input id="brname" type="text" style="width:15;" name="brname" |
| 2369 | 2369 | @ value="%h(zNewBranch)" onblur="defifempty(this)" onfocus="clrifsame(this)" |
| 2370 | - @ onkeyup="chgbn(this.value,'%h(zBranchName)')" /></td></tr> | |
| 2370 | + @ onkeyup="chgbn(this.value.trim(),'%h(zBranchName)')" /></td></tr> | |
| 2371 | 2371 | if( !fHasHidden ){ |
| 2372 | 2372 | @ <tr><th align="right" valign="top">Branch Hiding:</th> |
| 2373 | 2373 | @ <td valign="top"> |
| 2374 | 2374 | @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> |
| 2375 | 2375 | @ Hide branch |
| 2376 | 2376 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2214,18 +2214,18 @@ | |
| 2214 | ** clrifsame: clear the value if same as default. |
| 2215 | ** isempty: returns true if string has no non-whitespace characters. |
| 2216 | */ |
| 2217 | @ <script> |
| 2218 | @ function chgcbn(checked, branch){ |
| 2219 | @ val = gebi('brname').value; |
| 2220 | @ if( !val || !checked ) val = branch; |
| 2221 | @ gebi('hbranch').textContent = val; |
| 2222 | @ cidbrid = document.getElementById('cbranch'); |
| 2223 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2224 | @ } |
| 2225 | @ function chgbn(val, branch){ |
| 2226 | @ if( isempty(val) ) val = branch; |
| 2227 | @ gebi('newbr').checked = (val!=branch); |
| 2228 | @ gebi('hbranch').textContent = val; |
| 2229 | @ cidbrid = document.getElementById('cbranch'); |
| 2230 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2231 | @ } |
| @@ -2365,11 +2365,11 @@ | |
| 2365 | @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) |
| 2366 | @ onchange="chgcbn(this.checked,'%h(zBranchName)')" /> |
| 2367 | @ Make this check-in the start of a new branch named:</label> |
| 2368 | @ <input id="brname" type="text" style="width:15;" name="brname" |
| 2369 | @ value="%h(zNewBranch)" onblur="defifempty(this)" onfocus="clrifsame(this)" |
| 2370 | @ onkeyup="chgbn(this.value,'%h(zBranchName)')" /></td></tr> |
| 2371 | if( !fHasHidden ){ |
| 2372 | @ <tr><th align="right" valign="top">Branch Hiding:</th> |
| 2373 | @ <td valign="top"> |
| 2374 | @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> |
| 2375 | @ Hide branch |
| 2376 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2214,18 +2214,18 @@ | |
| 2214 | ** clrifsame: clear the value if same as default. |
| 2215 | ** isempty: returns true if string has no non-whitespace characters. |
| 2216 | */ |
| 2217 | @ <script> |
| 2218 | @ function chgcbn(checked, branch){ |
| 2219 | @ val = gebi('brname').value.trim(); |
| 2220 | @ if( !val || !checked ) val = branch; |
| 2221 | @ gebi('hbranch').textContent = val; |
| 2222 | @ cidbrid = document.getElementById('cbranch'); |
| 2223 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2224 | @ } |
| 2225 | @ function chgbn(val, branch){ |
| 2226 | @ if( !val ) val = branch; |
| 2227 | @ gebi('newbr').checked = (val!=branch); |
| 2228 | @ gebi('hbranch').textContent = val; |
| 2229 | @ cidbrid = document.getElementById('cbranch'); |
| 2230 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2231 | @ } |
| @@ -2365,11 +2365,11 @@ | |
| 2365 | @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) |
| 2366 | @ onchange="chgcbn(this.checked,'%h(zBranchName)')" /> |
| 2367 | @ Make this check-in the start of a new branch named:</label> |
| 2368 | @ <input id="brname" type="text" style="width:15;" name="brname" |
| 2369 | @ value="%h(zNewBranch)" onblur="defifempty(this)" onfocus="clrifsame(this)" |
| 2370 | @ onkeyup="chgbn(this.value.trim(),'%h(zBranchName)')" /></td></tr> |
| 2371 | if( !fHasHidden ){ |
| 2372 | @ <tr><th align="right" valign="top">Branch Hiding:</th> |
| 2373 | @ <td valign="top"> |
| 2374 | @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> |
| 2375 | @ Hide branch |
| 2376 |
+3
-3
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -2214,18 +2214,18 @@ | ||
| 2214 | 2214 | ** clrifsame: clear the value if same as default. |
| 2215 | 2215 | ** isempty: returns true if string has no non-whitespace characters. |
| 2216 | 2216 | */ |
| 2217 | 2217 | @ <script> |
| 2218 | 2218 | @ function chgcbn(checked, branch){ |
| 2219 | - @ val = gebi('brname').value; | |
| 2219 | + @ val = gebi('brname').value.trim(); | |
| 2220 | 2220 | @ if( !val || !checked ) val = branch; |
| 2221 | 2221 | @ gebi('hbranch').textContent = val; |
| 2222 | 2222 | @ cidbrid = document.getElementById('cbranch'); |
| 2223 | 2223 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2224 | 2224 | @ } |
| 2225 | 2225 | @ function chgbn(val, branch){ |
| 2226 | - @ if( isempty(val) ) val = branch; | |
| 2226 | + @ if( !val ) val = branch; | |
| 2227 | 2227 | @ gebi('newbr').checked = (val!=branch); |
| 2228 | 2228 | @ gebi('hbranch').textContent = val; |
| 2229 | 2229 | @ cidbrid = document.getElementById('cbranch'); |
| 2230 | 2230 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2231 | 2231 | @ } |
| @@ -2365,11 +2365,11 @@ | ||
| 2365 | 2365 | @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) |
| 2366 | 2366 | @ onchange="chgcbn(this.checked,'%h(zBranchName)')" /> |
| 2367 | 2367 | @ Make this check-in the start of a new branch named:</label> |
| 2368 | 2368 | @ <input id="brname" type="text" style="width:15;" name="brname" |
| 2369 | 2369 | @ value="%h(zNewBranch)" onblur="defifempty(this)" onfocus="clrifsame(this)" |
| 2370 | - @ onkeyup="chgbn(this.value,'%h(zBranchName)')" /></td></tr> | |
| 2370 | + @ onkeyup="chgbn(this.value.trim(),'%h(zBranchName)')" /></td></tr> | |
| 2371 | 2371 | if( !fHasHidden ){ |
| 2372 | 2372 | @ <tr><th align="right" valign="top">Branch Hiding:</th> |
| 2373 | 2373 | @ <td valign="top"> |
| 2374 | 2374 | @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> |
| 2375 | 2375 | @ Hide branch |
| 2376 | 2376 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2214,18 +2214,18 @@ | |
| 2214 | ** clrifsame: clear the value if same as default. |
| 2215 | ** isempty: returns true if string has no non-whitespace characters. |
| 2216 | */ |
| 2217 | @ <script> |
| 2218 | @ function chgcbn(checked, branch){ |
| 2219 | @ val = gebi('brname').value; |
| 2220 | @ if( !val || !checked ) val = branch; |
| 2221 | @ gebi('hbranch').textContent = val; |
| 2222 | @ cidbrid = document.getElementById('cbranch'); |
| 2223 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2224 | @ } |
| 2225 | @ function chgbn(val, branch){ |
| 2226 | @ if( isempty(val) ) val = branch; |
| 2227 | @ gebi('newbr').checked = (val!=branch); |
| 2228 | @ gebi('hbranch').textContent = val; |
| 2229 | @ cidbrid = document.getElementById('cbranch'); |
| 2230 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2231 | @ } |
| @@ -2365,11 +2365,11 @@ | |
| 2365 | @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) |
| 2366 | @ onchange="chgcbn(this.checked,'%h(zBranchName)')" /> |
| 2367 | @ Make this check-in the start of a new branch named:</label> |
| 2368 | @ <input id="brname" type="text" style="width:15;" name="brname" |
| 2369 | @ value="%h(zNewBranch)" onblur="defifempty(this)" onfocus="clrifsame(this)" |
| 2370 | @ onkeyup="chgbn(this.value,'%h(zBranchName)')" /></td></tr> |
| 2371 | if( !fHasHidden ){ |
| 2372 | @ <tr><th align="right" valign="top">Branch Hiding:</th> |
| 2373 | @ <td valign="top"> |
| 2374 | @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> |
| 2375 | @ Hide branch |
| 2376 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2214,18 +2214,18 @@ | |
| 2214 | ** clrifsame: clear the value if same as default. |
| 2215 | ** isempty: returns true if string has no non-whitespace characters. |
| 2216 | */ |
| 2217 | @ <script> |
| 2218 | @ function chgcbn(checked, branch){ |
| 2219 | @ val = gebi('brname').value.trim(); |
| 2220 | @ if( !val || !checked ) val = branch; |
| 2221 | @ gebi('hbranch').textContent = val; |
| 2222 | @ cidbrid = document.getElementById('cbranch'); |
| 2223 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2224 | @ } |
| 2225 | @ function chgbn(val, branch){ |
| 2226 | @ if( !val ) val = branch; |
| 2227 | @ gebi('newbr').checked = (val!=branch); |
| 2228 | @ gebi('hbranch').textContent = val; |
| 2229 | @ cidbrid = document.getElementById('cbranch'); |
| 2230 | @ if( cidbrid ) cidbrid.textContent = val; |
| 2231 | @ } |
| @@ -2365,11 +2365,11 @@ | |
| 2365 | @ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag) |
| 2366 | @ onchange="chgcbn(this.checked,'%h(zBranchName)')" /> |
| 2367 | @ Make this check-in the start of a new branch named:</label> |
| 2368 | @ <input id="brname" type="text" style="width:15;" name="brname" |
| 2369 | @ value="%h(zNewBranch)" onblur="defifempty(this)" onfocus="clrifsame(this)" |
| 2370 | @ onkeyup="chgbn(this.value.trim(),'%h(zBranchName)')" /></td></tr> |
| 2371 | if( !fHasHidden ){ |
| 2372 | @ <tr><th align="right" valign="top">Branch Hiding:</th> |
| 2373 | @ <td valign="top"> |
| 2374 | @ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) /> |
| 2375 | @ Hide branch |
| 2376 |
+1
-1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -580,11 +580,11 @@ | ||
| 580 | 580 | #endif |
| 581 | 581 | g.mainTimerId = fossil_timer_start(); |
| 582 | 582 | g.zVfsName = find_option("vfs",0,1); |
| 583 | 583 | if( g.zVfsName==0 ){ |
| 584 | 584 | g.zVfsName = fossil_getenv("FOSSIL_VFS"); |
| 585 | -#if defined(__CYGWIN__) | |
| 585 | +#if defined(_WIN32) || defined(__CYGWIN__) | |
| 586 | 586 | if( g.zVfsName==0 && sqlite3_libversion_number()>=3008001 ){ |
| 587 | 587 | g.zVfsName = "win32-longpath"; |
| 588 | 588 | } |
| 589 | 589 | #endif |
| 590 | 590 | } |
| 591 | 591 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -580,11 +580,11 @@ | |
| 580 | #endif |
| 581 | g.mainTimerId = fossil_timer_start(); |
| 582 | g.zVfsName = find_option("vfs",0,1); |
| 583 | if( g.zVfsName==0 ){ |
| 584 | g.zVfsName = fossil_getenv("FOSSIL_VFS"); |
| 585 | #if defined(__CYGWIN__) |
| 586 | if( g.zVfsName==0 && sqlite3_libversion_number()>=3008001 ){ |
| 587 | g.zVfsName = "win32-longpath"; |
| 588 | } |
| 589 | #endif |
| 590 | } |
| 591 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -580,11 +580,11 @@ | |
| 580 | #endif |
| 581 | g.mainTimerId = fossil_timer_start(); |
| 582 | g.zVfsName = find_option("vfs",0,1); |
| 583 | if( g.zVfsName==0 ){ |
| 584 | g.zVfsName = fossil_getenv("FOSSIL_VFS"); |
| 585 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 586 | if( g.zVfsName==0 && sqlite3_libversion_number()>=3008001 ){ |
| 587 | g.zVfsName = "win32-longpath"; |
| 588 | } |
| 589 | #endif |
| 590 | } |
| 591 |
+35
-5
| --- src/utf8.c | ||
| +++ src/utf8.c | ||
| @@ -191,22 +191,52 @@ | ||
| 191 | 191 | ** |
| 192 | 192 | */ |
| 193 | 193 | void *fossil_utf8_to_filename(const char *zUtf8){ |
| 194 | 194 | #ifdef _WIN32 |
| 195 | 195 | int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); |
| 196 | - wchar_t *zUnicode = sqlite3_malloc( nChar * 2 ); | |
| 196 | + /* Overallocate 6 chars, making some room for extended paths */ | |
| 197 | + wchar_t *zUnicode = sqlite3_malloc( (nChar+6) * sizeof(wchar_t) ); | |
| 197 | 198 | wchar_t *wUnicode = zUnicode; |
| 198 | 199 | if( zUnicode==0 ){ |
| 199 | 200 | return 0; |
| 200 | 201 | } |
| 201 | - MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); | |
| 202 | - /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */ | |
| 203 | 202 | if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':' |
| 204 | 203 | && (zUtf8[2]=='\\' || zUtf8[2]=='/')) { |
| 205 | - zUnicode[2] = '\\'; | |
| 206 | - wUnicode += 3; | |
| 204 | + /* If path starts with "<drive>:[/\]", don't process the ':' */ | |
| 205 | + if( nChar>MAX_PATH ) { | |
| 206 | + memcpy(zUnicode, L"\\\\?\\", 8); | |
| 207 | + wUnicode += 4; | |
| 208 | + MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, wUnicode, nChar); | |
| 209 | + wUnicode[2] = '\\'; | |
| 210 | + wUnicode += 3; | |
| 211 | + goto finish; | |
| 212 | + }else{ | |
| 213 | + zUnicode[0] = zUtf8[0]; | |
| 214 | + memcpy(&zUnicode[1], L":\\", 2 * sizeof(wchar_t)); | |
| 215 | + wUnicode += 3; | |
| 216 | + MultiByteToWideChar(CP_UTF8, 0, zUtf8+3, -1, wUnicode, nChar-3); | |
| 217 | + } | |
| 218 | + goto finish; | |
| 219 | + }else if( (zUtf8[0]=='\\' || zUtf8[0]=='/') && | |
| 220 | + (zUtf8[1]=='\\' || zUtf8[1]=='/') ) { | |
| 221 | + if (zUtf8[2]=='?' && nChar>5 ){ | |
| 222 | + /* Don't postprocess [?:] in extended path, but do '/' -> '\' */ | |
| 223 | + memcpy(zUnicode, L"\\\\", 2 * sizeof(wchar_t)); | |
| 224 | + MultiByteToWideChar(CP_UTF8, 0, zUtf8+2, -1, zUnicode+2, nChar-2); | |
| 225 | + if( zUtf8[3]=='/' ) zUnicode[3]='\\'; | |
| 226 | + wUnicode += 6; | |
| 227 | + goto finish; | |
| 228 | + }else if( nChar>MAX_PATH ){ | |
| 229 | + /* Convert to extended UNC path. */ | |
| 230 | + memcpy(zUnicode, L"\\\\?\\UNC\\", 16); | |
| 231 | + wUnicode += 8; | |
| 232 | + MultiByteToWideChar(CP_UTF8, 0, zUtf8+2, -1, wUnicode, nChar-8); | |
| 233 | + goto finish; | |
| 234 | + } | |
| 207 | 235 | } |
| 236 | + MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); | |
| 237 | +finish: | |
| 208 | 238 | while( *wUnicode != '\0' ){ |
| 209 | 239 | if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){ |
| 210 | 240 | *wUnicode |= 0xF000; |
| 211 | 241 | }else if( *wUnicode == '/' ){ |
| 212 | 242 | *wUnicode = '\\'; |
| 213 | 243 |
| --- src/utf8.c | |
| +++ src/utf8.c | |
| @@ -191,22 +191,52 @@ | |
| 191 | ** |
| 192 | */ |
| 193 | void *fossil_utf8_to_filename(const char *zUtf8){ |
| 194 | #ifdef _WIN32 |
| 195 | int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); |
| 196 | wchar_t *zUnicode = sqlite3_malloc( nChar * 2 ); |
| 197 | wchar_t *wUnicode = zUnicode; |
| 198 | if( zUnicode==0 ){ |
| 199 | return 0; |
| 200 | } |
| 201 | MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); |
| 202 | /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */ |
| 203 | if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':' |
| 204 | && (zUtf8[2]=='\\' || zUtf8[2]=='/')) { |
| 205 | zUnicode[2] = '\\'; |
| 206 | wUnicode += 3; |
| 207 | } |
| 208 | while( *wUnicode != '\0' ){ |
| 209 | if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){ |
| 210 | *wUnicode |= 0xF000; |
| 211 | }else if( *wUnicode == '/' ){ |
| 212 | *wUnicode = '\\'; |
| 213 |
| --- src/utf8.c | |
| +++ src/utf8.c | |
| @@ -191,22 +191,52 @@ | |
| 191 | ** |
| 192 | */ |
| 193 | void *fossil_utf8_to_filename(const char *zUtf8){ |
| 194 | #ifdef _WIN32 |
| 195 | int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); |
| 196 | /* Overallocate 6 chars, making some room for extended paths */ |
| 197 | wchar_t *zUnicode = sqlite3_malloc( (nChar+6) * sizeof(wchar_t) ); |
| 198 | wchar_t *wUnicode = zUnicode; |
| 199 | if( zUnicode==0 ){ |
| 200 | return 0; |
| 201 | } |
| 202 | if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':' |
| 203 | && (zUtf8[2]=='\\' || zUtf8[2]=='/')) { |
| 204 | /* If path starts with "<drive>:[/\]", don't process the ':' */ |
| 205 | if( nChar>MAX_PATH ) { |
| 206 | memcpy(zUnicode, L"\\\\?\\", 8); |
| 207 | wUnicode += 4; |
| 208 | MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, wUnicode, nChar); |
| 209 | wUnicode[2] = '\\'; |
| 210 | wUnicode += 3; |
| 211 | goto finish; |
| 212 | }else{ |
| 213 | zUnicode[0] = zUtf8[0]; |
| 214 | memcpy(&zUnicode[1], L":\\", 2 * sizeof(wchar_t)); |
| 215 | wUnicode += 3; |
| 216 | MultiByteToWideChar(CP_UTF8, 0, zUtf8+3, -1, wUnicode, nChar-3); |
| 217 | } |
| 218 | goto finish; |
| 219 | }else if( (zUtf8[0]=='\\' || zUtf8[0]=='/') && |
| 220 | (zUtf8[1]=='\\' || zUtf8[1]=='/') ) { |
| 221 | if (zUtf8[2]=='?' && nChar>5 ){ |
| 222 | /* Don't postprocess [?:] in extended path, but do '/' -> '\' */ |
| 223 | memcpy(zUnicode, L"\\\\", 2 * sizeof(wchar_t)); |
| 224 | MultiByteToWideChar(CP_UTF8, 0, zUtf8+2, -1, zUnicode+2, nChar-2); |
| 225 | if( zUtf8[3]=='/' ) zUnicode[3]='\\'; |
| 226 | wUnicode += 6; |
| 227 | goto finish; |
| 228 | }else if( nChar>MAX_PATH ){ |
| 229 | /* Convert to extended UNC path. */ |
| 230 | memcpy(zUnicode, L"\\\\?\\UNC\\", 16); |
| 231 | wUnicode += 8; |
| 232 | MultiByteToWideChar(CP_UTF8, 0, zUtf8+2, -1, wUnicode, nChar-8); |
| 233 | goto finish; |
| 234 | } |
| 235 | } |
| 236 | MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); |
| 237 | finish: |
| 238 | while( *wUnicode != '\0' ){ |
| 239 | if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){ |
| 240 | *wUnicode |= 0xF000; |
| 241 | }else if( *wUnicode == '/' ){ |
| 242 | *wUnicode = '\\'; |
| 243 |
+3
-3
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -27,11 +27,11 @@ | ||
| 27 | 27 | ** Return true if the input string is a well-formed wiki page name. |
| 28 | 28 | ** |
| 29 | 29 | ** Well-formed wiki page names do not begin or end with whitespace, |
| 30 | 30 | ** and do not contain tabs or other control characters and do not |
| 31 | 31 | ** contain more than a single space character in a row. Well-formed |
| 32 | -** names must be between 3 and 100 characters in length, inclusive. | |
| 32 | +** names must be between 1 and 100 characters in length, inclusive. | |
| 33 | 33 | */ |
| 34 | 34 | int wiki_name_is_wellformed(const unsigned char *z){ |
| 35 | 35 | int i; |
| 36 | 36 | if( z[0]<=0x20 ){ |
| 37 | 37 | return 0; |
| @@ -39,11 +39,11 @@ | ||
| 39 | 39 | for(i=1; z[i]; i++){ |
| 40 | 40 | if( z[i]<0x20 ) return 0; |
| 41 | 41 | if( z[i]==0x20 && z[i-1]==0x20 ) return 0; |
| 42 | 42 | } |
| 43 | 43 | if( z[i-1]==' ' ) return 0; |
| 44 | - if( i<3 || i>100 ) return 0; | |
| 44 | + if( i<1 || i>100 ) return 0; | |
| 45 | 45 | return 1; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | 48 | /* |
| 49 | 49 | ** Output rules for well-formed wiki pages |
| @@ -52,11 +52,11 @@ | ||
| 52 | 52 | @ <ul> |
| 53 | 53 | @ <li> Must not begin or end with a space.</li> |
| 54 | 54 | @ <li> Must not contain any control characters, including tab or |
| 55 | 55 | @ newline.</li> |
| 56 | 56 | @ <li> Must not have two or more spaces in a row internally.</li> |
| 57 | - @ <li> Must be between 3 and 100 characters in length.</li> | |
| 57 | + @ <li> Must be between 1 and 100 characters in length.</li> | |
| 58 | 58 | @ </ul> |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | /* |
| 62 | 62 | ** Check a wiki name. If it is not well-formed, then issue an error |
| 63 | 63 | |
| 64 | 64 | ADDED test/win32-longpath.test |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -27,11 +27,11 @@ | |
| 27 | ** Return true if the input string is a well-formed wiki page name. |
| 28 | ** |
| 29 | ** Well-formed wiki page names do not begin or end with whitespace, |
| 30 | ** and do not contain tabs or other control characters and do not |
| 31 | ** contain more than a single space character in a row. Well-formed |
| 32 | ** names must be between 3 and 100 characters in length, inclusive. |
| 33 | */ |
| 34 | int wiki_name_is_wellformed(const unsigned char *z){ |
| 35 | int i; |
| 36 | if( z[0]<=0x20 ){ |
| 37 | return 0; |
| @@ -39,11 +39,11 @@ | |
| 39 | for(i=1; z[i]; i++){ |
| 40 | if( z[i]<0x20 ) return 0; |
| 41 | if( z[i]==0x20 && z[i-1]==0x20 ) return 0; |
| 42 | } |
| 43 | if( z[i-1]==' ' ) return 0; |
| 44 | if( i<3 || i>100 ) return 0; |
| 45 | return 1; |
| 46 | } |
| 47 | |
| 48 | /* |
| 49 | ** Output rules for well-formed wiki pages |
| @@ -52,11 +52,11 @@ | |
| 52 | @ <ul> |
| 53 | @ <li> Must not begin or end with a space.</li> |
| 54 | @ <li> Must not contain any control characters, including tab or |
| 55 | @ newline.</li> |
| 56 | @ <li> Must not have two or more spaces in a row internally.</li> |
| 57 | @ <li> Must be between 3 and 100 characters in length.</li> |
| 58 | @ </ul> |
| 59 | } |
| 60 | |
| 61 | /* |
| 62 | ** Check a wiki name. If it is not well-formed, then issue an error |
| 63 | |
| 64 | DDED test/win32-longpath.test |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -27,11 +27,11 @@ | |
| 27 | ** Return true if the input string is a well-formed wiki page name. |
| 28 | ** |
| 29 | ** Well-formed wiki page names do not begin or end with whitespace, |
| 30 | ** and do not contain tabs or other control characters and do not |
| 31 | ** contain more than a single space character in a row. Well-formed |
| 32 | ** names must be between 1 and 100 characters in length, inclusive. |
| 33 | */ |
| 34 | int wiki_name_is_wellformed(const unsigned char *z){ |
| 35 | int i; |
| 36 | if( z[0]<=0x20 ){ |
| 37 | return 0; |
| @@ -39,11 +39,11 @@ | |
| 39 | for(i=1; z[i]; i++){ |
| 40 | if( z[i]<0x20 ) return 0; |
| 41 | if( z[i]==0x20 && z[i-1]==0x20 ) return 0; |
| 42 | } |
| 43 | if( z[i-1]==' ' ) return 0; |
| 44 | if( i<1 || i>100 ) return 0; |
| 45 | return 1; |
| 46 | } |
| 47 | |
| 48 | /* |
| 49 | ** Output rules for well-formed wiki pages |
| @@ -52,11 +52,11 @@ | |
| 52 | @ <ul> |
| 53 | @ <li> Must not begin or end with a space.</li> |
| 54 | @ <li> Must not contain any control characters, including tab or |
| 55 | @ newline.</li> |
| 56 | @ <li> Must not have two or more spaces in a row internally.</li> |
| 57 | @ <li> Must be between 1 and 100 characters in length.</li> |
| 58 | @ </ul> |
| 59 | } |
| 60 | |
| 61 | /* |
| 62 | ** Check a wiki name. If it is not well-formed, then issue an error |
| 63 | |
| 64 | DDED test/win32-longpath.test |
+32
| --- a/test/win32-longpath.test | ||
| +++ b/test/win32-longpath.test | ||
| @@ -0,0 +1,32 @@ | ||
| 1 | +# | |
| 2 | +# Tests for 'win32-longpath' VFS, using a repo path >260 chars. | |
| 3 | +# | |
| 4 | +# Actually, this test should pass on any platform. | |
| 5 | +# | |
| 6 | + | |
| 7 | +# Fossil will write data on $HOME, running 'fossil new' here. | |
| 8 | +# We need not to clutter the $HOME of the test caller. | |
| 9 | +# | |
| 10 | +set env(HOME) [pwd] | |
| 11 | + | |
| 12 | +# Create the repo | |
| 13 | +# | |
| 14 | +set x [string repeat x 132] | |
| 15 | +set longpath [pwd]/$x | |
| 16 | +file mkdir $longpath | |
| 17 | +catch { | |
| 18 | + # Use "cygpath" for converting it to win32 path. If not | |
| 19 | + # in Msys or Cygwin shell, nothing needs to be done. | |
| 20 | + set longpath [exec cygpath -w $longpath] | |
| 21 | +} | |
| 22 | + | |
| 23 | +test win32-longpath-test.1 { | |
| 24 | + ![regexp CANTOPEN [fossil new $longpath/$x.fossil]] | |
| 25 | +} | |
| 26 | + | |
| 27 | +# Try to remove the file/dir various ways, different | |
| 28 | +# Shells/Tcl versions expect it differently. | |
| 29 | +catch {file delete \\\\?\\$longpath\\$x.fossil} | |
| 30 | +catch {file delete $longpath/$x.fossil} | |
| 31 | +catch {file delete [pwd]/$x/$x.fossil} | |
| 32 | +catch {file delete [pwd]/$x} |
| --- a/test/win32-longpath.test | |
| +++ b/test/win32-longpath.test | |
| @@ -0,0 +1,32 @@ | |
| --- a/test/win32-longpath.test | |
| +++ b/test/win32-longpath.test | |
| @@ -0,0 +1,32 @@ | |
| 1 | # |
| 2 | # Tests for 'win32-longpath' VFS, using a repo path >260 chars. |
| 3 | # |
| 4 | # Actually, this test should pass on any platform. |
| 5 | # |
| 6 | |
| 7 | # Fossil will write data on $HOME, running 'fossil new' here. |
| 8 | # We need not to clutter the $HOME of the test caller. |
| 9 | # |
| 10 | set env(HOME) [pwd] |
| 11 | |
| 12 | # Create the repo |
| 13 | # |
| 14 | set x [string repeat x 132] |
| 15 | set longpath [pwd]/$x |
| 16 | file mkdir $longpath |
| 17 | catch { |
| 18 | # Use "cygpath" for converting it to win32 path. If not |
| 19 | # in Msys or Cygwin shell, nothing needs to be done. |
| 20 | set longpath [exec cygpath -w $longpath] |
| 21 | } |
| 22 | |
| 23 | test win32-longpath-test.1 { |
| 24 | ![regexp CANTOPEN [fossil new $longpath/$x.fossil]] |
| 25 | } |
| 26 | |
| 27 | # Try to remove the file/dir various ways, different |
| 28 | # Shells/Tcl versions expect it differently. |
| 29 | catch {file delete \\\\?\\$longpath\\$x.fossil} |
| 30 | catch {file delete $longpath/$x.fossil} |
| 31 | catch {file delete [pwd]/$x/$x.fossil} |
| 32 | catch {file delete [pwd]/$x} |