Fossil SCM
On file listing pages, sort files that have numbers as part of their name in numeric order.
Commit
59dfca5ed575d6e321b895e392ca21405eedf13618254dc856f331ce866e3c66
Parent
8736de8baad75d2…
2 files changed
+5
-4
+53
+5
-4
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -330,11 +330,12 @@ | ||
| 330 | 330 | ** directory. |
| 331 | 331 | */ |
| 332 | 332 | mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); |
| 333 | 333 | if( mxLen<12 ) mxLen = 12; |
| 334 | 334 | mxLen += (mxLen+9)/10; |
| 335 | - db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/"); | |
| 335 | + db_prepare(&q, | |
| 336 | + "SELECT x, u FROM localfiles ORDER BY x COLLATE uintnocase /*scan*/"); | |
| 336 | 337 | @ <div class="columns files" style="columns: %d(mxLen)ex auto"> |
| 337 | 338 | @ <ul class="browser"> |
| 338 | 339 | while( db_step(&q)==SQLITE_ROW ){ |
| 339 | 340 | const char *zFN; |
| 340 | 341 | zFN = db_column_text(&q, 0); |
| @@ -368,11 +369,11 @@ | ||
| 368 | 369 | */ |
| 369 | 370 | db_prepare(&q, |
| 370 | 371 | "SELECT x, u FROM localfiles" |
| 371 | 372 | " WHERE x COLLATE nocase IN" |
| 372 | 373 | " ('readme','readme.txt','readme.md','readme.wiki','readme.markdown'," |
| 373 | - " 'readme.html') ORDER BY x LIMIT 1;" | |
| 374 | + " 'readme.html') ORDER BY x COLLATE uintnocase LIMIT 1;" | |
| 374 | 375 | ); |
| 375 | 376 | if( db_step(&q)==SQLITE_ROW ){ |
| 376 | 377 | const char *zName = db_column_text(&q,0); |
| 377 | 378 | const char *zUuid = db_column_text(&q,1); |
| 378 | 379 | if( zUuid ){ |
| @@ -790,11 +791,11 @@ | ||
| 790 | 791 | db_prepare(&q, |
| 791 | 792 | "SELECT filename.name, blob.uuid, fileage.mtime\n" |
| 792 | 793 | " FROM fileage, filename, blob\n" |
| 793 | 794 | " WHERE filename.fnid=fileage.fnid\n" |
| 794 | 795 | " AND blob.rid=fileage.fid\n" |
| 795 | - " ORDER BY filename.name COLLATE nocase;" | |
| 796 | + " ORDER BY filename.name COLLATE uintnocase;" | |
| 796 | 797 | ); |
| 797 | 798 | while( db_step(&q)==SQLITE_ROW ){ |
| 798 | 799 | const char *zFile = db_column_text(&q,0); |
| 799 | 800 | const char *zUuid = db_column_text(&q,1); |
| 800 | 801 | double mtime = db_column_double(&q,2); |
| @@ -813,11 +814,11 @@ | ||
| 813 | 814 | " (SELECT name FROM filename WHERE filename.fnid=mlink.fnid),\n" |
| 814 | 815 | " (SELECT uuid FROM blob WHERE blob.rid=mlink.fid),\n" |
| 815 | 816 | " max(event.mtime)\n" |
| 816 | 817 | " FROM mlink JOIN event ON event.objid=mlink.mid\n" |
| 817 | 818 | " GROUP BY mlink.fnid\n" |
| 818 | - " ORDER BY 1 COLLATE nocase;"); | |
| 819 | + " ORDER BY 1 COLLATE uintnocase;"); | |
| 819 | 820 | while( db_step(&q)==SQLITE_ROW ){ |
| 820 | 821 | const char *zName = db_column_text(&q, 0); |
| 821 | 822 | const char *zUuid = db_column_text(&q,1); |
| 822 | 823 | double mtime = db_column_double(&q,2); |
| 823 | 824 | if( nD>0 && (fossil_strncmp(zName, zD, nD-1)!=0 || zName[nD-1]!='/') ){ |
| 824 | 825 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -330,11 +330,12 @@ | |
| 330 | ** directory. |
| 331 | */ |
| 332 | mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); |
| 333 | if( mxLen<12 ) mxLen = 12; |
| 334 | mxLen += (mxLen+9)/10; |
| 335 | db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/"); |
| 336 | @ <div class="columns files" style="columns: %d(mxLen)ex auto"> |
| 337 | @ <ul class="browser"> |
| 338 | while( db_step(&q)==SQLITE_ROW ){ |
| 339 | const char *zFN; |
| 340 | zFN = db_column_text(&q, 0); |
| @@ -368,11 +369,11 @@ | |
| 368 | */ |
| 369 | db_prepare(&q, |
| 370 | "SELECT x, u FROM localfiles" |
| 371 | " WHERE x COLLATE nocase IN" |
| 372 | " ('readme','readme.txt','readme.md','readme.wiki','readme.markdown'," |
| 373 | " 'readme.html') ORDER BY x LIMIT 1;" |
| 374 | ); |
| 375 | if( db_step(&q)==SQLITE_ROW ){ |
| 376 | const char *zName = db_column_text(&q,0); |
| 377 | const char *zUuid = db_column_text(&q,1); |
| 378 | if( zUuid ){ |
| @@ -790,11 +791,11 @@ | |
| 790 | db_prepare(&q, |
| 791 | "SELECT filename.name, blob.uuid, fileage.mtime\n" |
| 792 | " FROM fileage, filename, blob\n" |
| 793 | " WHERE filename.fnid=fileage.fnid\n" |
| 794 | " AND blob.rid=fileage.fid\n" |
| 795 | " ORDER BY filename.name COLLATE nocase;" |
| 796 | ); |
| 797 | while( db_step(&q)==SQLITE_ROW ){ |
| 798 | const char *zFile = db_column_text(&q,0); |
| 799 | const char *zUuid = db_column_text(&q,1); |
| 800 | double mtime = db_column_double(&q,2); |
| @@ -813,11 +814,11 @@ | |
| 813 | " (SELECT name FROM filename WHERE filename.fnid=mlink.fnid),\n" |
| 814 | " (SELECT uuid FROM blob WHERE blob.rid=mlink.fid),\n" |
| 815 | " max(event.mtime)\n" |
| 816 | " FROM mlink JOIN event ON event.objid=mlink.mid\n" |
| 817 | " GROUP BY mlink.fnid\n" |
| 818 | " ORDER BY 1 COLLATE nocase;"); |
| 819 | while( db_step(&q)==SQLITE_ROW ){ |
| 820 | const char *zName = db_column_text(&q, 0); |
| 821 | const char *zUuid = db_column_text(&q,1); |
| 822 | double mtime = db_column_double(&q,2); |
| 823 | if( nD>0 && (fossil_strncmp(zName, zD, nD-1)!=0 || zName[nD-1]!='/') ){ |
| 824 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -330,11 +330,12 @@ | |
| 330 | ** directory. |
| 331 | */ |
| 332 | mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); |
| 333 | if( mxLen<12 ) mxLen = 12; |
| 334 | mxLen += (mxLen+9)/10; |
| 335 | db_prepare(&q, |
| 336 | "SELECT x, u FROM localfiles ORDER BY x COLLATE uintnocase /*scan*/"); |
| 337 | @ <div class="columns files" style="columns: %d(mxLen)ex auto"> |
| 338 | @ <ul class="browser"> |
| 339 | while( db_step(&q)==SQLITE_ROW ){ |
| 340 | const char *zFN; |
| 341 | zFN = db_column_text(&q, 0); |
| @@ -368,11 +369,11 @@ | |
| 369 | */ |
| 370 | db_prepare(&q, |
| 371 | "SELECT x, u FROM localfiles" |
| 372 | " WHERE x COLLATE nocase IN" |
| 373 | " ('readme','readme.txt','readme.md','readme.wiki','readme.markdown'," |
| 374 | " 'readme.html') ORDER BY x COLLATE uintnocase LIMIT 1;" |
| 375 | ); |
| 376 | if( db_step(&q)==SQLITE_ROW ){ |
| 377 | const char *zName = db_column_text(&q,0); |
| 378 | const char *zUuid = db_column_text(&q,1); |
| 379 | if( zUuid ){ |
| @@ -790,11 +791,11 @@ | |
| 791 | db_prepare(&q, |
| 792 | "SELECT filename.name, blob.uuid, fileage.mtime\n" |
| 793 | " FROM fileage, filename, blob\n" |
| 794 | " WHERE filename.fnid=fileage.fnid\n" |
| 795 | " AND blob.rid=fileage.fid\n" |
| 796 | " ORDER BY filename.name COLLATE uintnocase;" |
| 797 | ); |
| 798 | while( db_step(&q)==SQLITE_ROW ){ |
| 799 | const char *zFile = db_column_text(&q,0); |
| 800 | const char *zUuid = db_column_text(&q,1); |
| 801 | double mtime = db_column_double(&q,2); |
| @@ -813,11 +814,11 @@ | |
| 814 | " (SELECT name FROM filename WHERE filename.fnid=mlink.fnid),\n" |
| 815 | " (SELECT uuid FROM blob WHERE blob.rid=mlink.fid),\n" |
| 816 | " max(event.mtime)\n" |
| 817 | " FROM mlink JOIN event ON event.objid=mlink.mid\n" |
| 818 | " GROUP BY mlink.fnid\n" |
| 819 | " ORDER BY 1 COLLATE uintnocase;"); |
| 820 | while( db_step(&q)==SQLITE_ROW ){ |
| 821 | const char *zName = db_column_text(&q, 0); |
| 822 | const char *zUuid = db_column_text(&q,1); |
| 823 | double mtime = db_column_double(&q,2); |
| 824 | if( nD>0 && (fossil_strncmp(zName, zD, nD-1)!=0 || zName[nD-1]!='/') ){ |
| 825 |
M
src/db.c
+53
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1376,16 +1376,69 @@ | ||
| 1376 | 1376 | return; |
| 1377 | 1377 | } |
| 1378 | 1378 | zSetting = (const char*)sqlite3_value_text(argv[0]); |
| 1379 | 1379 | sqlite3_result_int(context, db_setting_is_protected(zSetting)); |
| 1380 | 1380 | } |
| 1381 | + | |
| 1382 | +/* | |
| 1383 | +** Copied from SQLite ext/misc/uint.c... | |
| 1384 | +** | |
| 1385 | +** Compare text in lexicographic order, except strings of digits | |
| 1386 | +** compare in numeric order. | |
| 1387 | +** | |
| 1388 | +** This version modified to also ignore case. | |
| 1389 | +*/ | |
| 1390 | +static int uintNocaseCollFunc( | |
| 1391 | + void *notUsed, | |
| 1392 | + int nKey1, const void *pKey1, | |
| 1393 | + int nKey2, const void *pKey2 | |
| 1394 | +){ | |
| 1395 | + const unsigned char *zA = (const unsigned char*)pKey1; | |
| 1396 | + const unsigned char *zB = (const unsigned char*)pKey2; | |
| 1397 | + int i=0, j=0, x; | |
| 1398 | + (void)notUsed; | |
| 1399 | + while( i<nKey1 && j<nKey2 ){ | |
| 1400 | + if( fossil_isdigit(zA[i]) ){ | |
| 1401 | + int k; | |
| 1402 | + if( !fossil_isdigit(zB[j]) ) return x; | |
| 1403 | + while( i<nKey1 && zA[i]=='0' ){ i++; } | |
| 1404 | + while( j<nKey2 && zB[j]=='0' ){ j++; } | |
| 1405 | + k = 0; | |
| 1406 | + while( i+k<nKey1 && fossil_isdigit(zA[i+k]) | |
| 1407 | + && j+k<nKey2 && fossil_isdigit(zB[j+k]) ){ | |
| 1408 | + k++; | |
| 1409 | + } | |
| 1410 | + if( i+k<nKey1 && fossil_isdigit(zA[i+k]) ){ | |
| 1411 | + return +1; | |
| 1412 | + }else if( j+k<nKey2 && fossil_isdigit(zB[j+k]) ){ | |
| 1413 | + return -1; | |
| 1414 | + }else{ | |
| 1415 | + x = memcmp(zA+i, zB+j, k); | |
| 1416 | + if( x ) return x; | |
| 1417 | + i += k; | |
| 1418 | + j += k; | |
| 1419 | + } | |
| 1420 | + }else | |
| 1421 | + if( zA[i]!=zB[j] | |
| 1422 | + && (x = fossil_tolower(zA[i]) - fossil_tolower(zB[j]))!=0 | |
| 1423 | + ){ | |
| 1424 | + return x; | |
| 1425 | + }else{ | |
| 1426 | + i++; | |
| 1427 | + j++; | |
| 1428 | + } | |
| 1429 | + } | |
| 1430 | + return (nKey1 - i) - (nKey2 - j); | |
| 1431 | +} | |
| 1432 | + | |
| 1381 | 1433 | |
| 1382 | 1434 | /* |
| 1383 | 1435 | ** Register the SQL functions that are useful both to the internal |
| 1384 | 1436 | ** representation and to the "fossil sql" command. |
| 1385 | 1437 | */ |
| 1386 | 1438 | void db_add_aux_functions(sqlite3 *db){ |
| 1439 | + sqlite3_create_collation(db, "uintnocase", SQLITE_UTF8,0,uintNocaseCollFunc); | |
| 1387 | 1440 | sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0, |
| 1388 | 1441 | db_checkin_mtime_function, 0, 0); |
| 1389 | 1442 | sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, |
| 1390 | 1443 | db_sym2rid_function, 0, 0); |
| 1391 | 1444 | sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, |
| 1392 | 1445 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1376,16 +1376,69 @@ | |
| 1376 | return; |
| 1377 | } |
| 1378 | zSetting = (const char*)sqlite3_value_text(argv[0]); |
| 1379 | sqlite3_result_int(context, db_setting_is_protected(zSetting)); |
| 1380 | } |
| 1381 | |
| 1382 | /* |
| 1383 | ** Register the SQL functions that are useful both to the internal |
| 1384 | ** representation and to the "fossil sql" command. |
| 1385 | */ |
| 1386 | void db_add_aux_functions(sqlite3 *db){ |
| 1387 | sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0, |
| 1388 | db_checkin_mtime_function, 0, 0); |
| 1389 | sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, |
| 1390 | db_sym2rid_function, 0, 0); |
| 1391 | sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, |
| 1392 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1376,16 +1376,69 @@ | |
| 1376 | return; |
| 1377 | } |
| 1378 | zSetting = (const char*)sqlite3_value_text(argv[0]); |
| 1379 | sqlite3_result_int(context, db_setting_is_protected(zSetting)); |
| 1380 | } |
| 1381 | |
| 1382 | /* |
| 1383 | ** Copied from SQLite ext/misc/uint.c... |
| 1384 | ** |
| 1385 | ** Compare text in lexicographic order, except strings of digits |
| 1386 | ** compare in numeric order. |
| 1387 | ** |
| 1388 | ** This version modified to also ignore case. |
| 1389 | */ |
| 1390 | static int uintNocaseCollFunc( |
| 1391 | void *notUsed, |
| 1392 | int nKey1, const void *pKey1, |
| 1393 | int nKey2, const void *pKey2 |
| 1394 | ){ |
| 1395 | const unsigned char *zA = (const unsigned char*)pKey1; |
| 1396 | const unsigned char *zB = (const unsigned char*)pKey2; |
| 1397 | int i=0, j=0, x; |
| 1398 | (void)notUsed; |
| 1399 | while( i<nKey1 && j<nKey2 ){ |
| 1400 | if( fossil_isdigit(zA[i]) ){ |
| 1401 | int k; |
| 1402 | if( !fossil_isdigit(zB[j]) ) return x; |
| 1403 | while( i<nKey1 && zA[i]=='0' ){ i++; } |
| 1404 | while( j<nKey2 && zB[j]=='0' ){ j++; } |
| 1405 | k = 0; |
| 1406 | while( i+k<nKey1 && fossil_isdigit(zA[i+k]) |
| 1407 | && j+k<nKey2 && fossil_isdigit(zB[j+k]) ){ |
| 1408 | k++; |
| 1409 | } |
| 1410 | if( i+k<nKey1 && fossil_isdigit(zA[i+k]) ){ |
| 1411 | return +1; |
| 1412 | }else if( j+k<nKey2 && fossil_isdigit(zB[j+k]) ){ |
| 1413 | return -1; |
| 1414 | }else{ |
| 1415 | x = memcmp(zA+i, zB+j, k); |
| 1416 | if( x ) return x; |
| 1417 | i += k; |
| 1418 | j += k; |
| 1419 | } |
| 1420 | }else |
| 1421 | if( zA[i]!=zB[j] |
| 1422 | && (x = fossil_tolower(zA[i]) - fossil_tolower(zB[j]))!=0 |
| 1423 | ){ |
| 1424 | return x; |
| 1425 | }else{ |
| 1426 | i++; |
| 1427 | j++; |
| 1428 | } |
| 1429 | } |
| 1430 | return (nKey1 - i) - (nKey2 - j); |
| 1431 | } |
| 1432 | |
| 1433 | |
| 1434 | /* |
| 1435 | ** Register the SQL functions that are useful both to the internal |
| 1436 | ** representation and to the "fossil sql" command. |
| 1437 | */ |
| 1438 | void db_add_aux_functions(sqlite3 *db){ |
| 1439 | sqlite3_create_collation(db, "uintnocase", SQLITE_UTF8,0,uintNocaseCollFunc); |
| 1440 | sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0, |
| 1441 | db_checkin_mtime_function, 0, 0); |
| 1442 | sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, |
| 1443 | db_sym2rid_function, 0, 0); |
| 1444 | sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, |
| 1445 |