Fossil SCM

Merged in mimetypes-setting branch.

stephan 2020-01-28 06:40 trunk merge
Commit 009a24313bb6e509a81cd5a0fcda1dd1379cb3ce901e8eaaa1d7a0fcb527cd81
--- src/configure.c
+++ src/configure.c
@@ -143,10 +143,11 @@
143143
{ "dotfiles", CONFIGSET_PROJ },
144144
{ "parent-project-code", CONFIGSET_PROJ },
145145
{ "parent-project-name", CONFIGSET_PROJ },
146146
{ "hash-policy", CONFIGSET_PROJ },
147147
{ "comment-format", CONFIGSET_PROJ },
148
+ { "mimetypes", CONFIGSET_PROJ },
148149
149150
#ifdef FOSSIL_ENABLE_LEGACY_MV_RM
150151
{ "mv-rm-files", CONFIGSET_PROJ },
151152
#endif
152153
153154
--- src/configure.c
+++ src/configure.c
@@ -143,10 +143,11 @@
143 { "dotfiles", CONFIGSET_PROJ },
144 { "parent-project-code", CONFIGSET_PROJ },
145 { "parent-project-name", CONFIGSET_PROJ },
146 { "hash-policy", CONFIGSET_PROJ },
147 { "comment-format", CONFIGSET_PROJ },
 
148
149 #ifdef FOSSIL_ENABLE_LEGACY_MV_RM
150 { "mv-rm-files", CONFIGSET_PROJ },
151 #endif
152
153
--- src/configure.c
+++ src/configure.c
@@ -143,10 +143,11 @@
143 { "dotfiles", CONFIGSET_PROJ },
144 { "parent-project-code", CONFIGSET_PROJ },
145 { "parent-project-name", CONFIGSET_PROJ },
146 { "hash-policy", CONFIGSET_PROJ },
147 { "comment-format", CONFIGSET_PROJ },
148 { "mimetypes", CONFIGSET_PROJ },
149
150 #ifdef FOSSIL_ENABLE_LEGACY_MV_RM
151 { "mv-rm-files", CONFIGSET_PROJ },
152 #endif
153
154
+7
--- src/db.c
+++ src/db.c
@@ -3449,10 +3449,17 @@
34493449
*/
34503450
/*
34513451
** SETTING: max-upload width=25 default=250000
34523452
** A limit on the size of uplink HTTP requests.
34533453
*/
3454
+/*
3455
+** SETTING: mimetypes width=40 versionable block-text
3456
+** A list of file extension-to-mimetype mappings, one per line. e.g.
3457
+** "foo application/x-foo". File extensions are compared
3458
+** case-insensitively in the order listed in this setting. A leading
3459
+** '.' on file extensions is permitted but not required.
3460
+*/
34543461
/*
34553462
** SETTING: mtime-changes boolean default=on
34563463
** Use file modification times (mtimes) to detect when
34573464
** files have been modified. If disabled, all managed files
34583465
** are hashed to detect changes, which can be slow for large
34593466
--- src/db.c
+++ src/db.c
@@ -3449,10 +3449,17 @@
3449 */
3450 /*
3451 ** SETTING: max-upload width=25 default=250000
3452 ** A limit on the size of uplink HTTP requests.
3453 */
 
 
 
 
 
 
 
3454 /*
3455 ** SETTING: mtime-changes boolean default=on
3456 ** Use file modification times (mtimes) to detect when
3457 ** files have been modified. If disabled, all managed files
3458 ** are hashed to detect changes, which can be slow for large
3459
--- src/db.c
+++ src/db.c
@@ -3449,10 +3449,17 @@
3449 */
3450 /*
3451 ** SETTING: max-upload width=25 default=250000
3452 ** A limit on the size of uplink HTTP requests.
3453 */
3454 /*
3455 ** SETTING: mimetypes width=40 versionable block-text
3456 ** A list of file extension-to-mimetype mappings, one per line. e.g.
3457 ** "foo application/x-foo". File extensions are compared
3458 ** case-insensitively in the order listed in this setting. A leading
3459 ** '.' on file extensions is permitted but not required.
3460 */
3461 /*
3462 ** SETTING: mtime-changes boolean default=on
3463 ** Use file modification times (mtimes) to detect when
3464 ** files have been modified. If disabled, all managed files
3465 ** are hashed to detect changes, which can be slow for large
3466
+145 -3
--- src/doc.c
+++ src/doc.c
@@ -304,10 +304,103 @@
304304
fossil_panic("mimetypes out of sequence: %s before %s",
305305
aMime[i-1].zSuffix, aMime[i].zSuffix);
306306
}
307307
}
308308
}
309
+
310
+/*
311
+** Looks in the contents of the "mimetypes" setting for a suffix
312
+** matching zSuffix. If found, it returns the configured value
313
+** in memory owned by the app (i.e. do not free() it), else it
314
+** returns 0.
315
+**
316
+** The mimetypes setting is expected to be a list of file extensions
317
+** and mimetypes, with one such mapping per line. A leading '.' on
318
+** extensions is permitted for compatibility with lists imported from
319
+** other tools which require them.
320
+*/
321
+static const char *mimetype_from_name_custom(const char *zSuffix){
322
+ static char * zList = 0;
323
+ static char const * zEnd = 0;
324
+ static int once = 0;
325
+ char * z;
326
+ int tokenizerState /* 0=expecting a key, 1=skip next token,
327
+ ** 2=accept next token */;
328
+ if(once==0){
329
+ once = 1;
330
+ zList = db_get("mimetypes",0);
331
+ if(zList==0){
332
+ return 0;
333
+ }
334
+ /* Transform zList to simplify the main loop:
335
+ replace non-newline spaces with NUL bytes. */
336
+ zEnd = zList + strlen(zList);
337
+ for(z = zList; z<zEnd; ++z){
338
+ if('\n'==*z) continue;
339
+ else if(fossil_isspace(*z)){
340
+ *z = 0;
341
+ }
342
+ }
343
+ }else if(zList==0){
344
+ return 0;
345
+ }
346
+ tokenizerState = 0;
347
+ z = zList;
348
+ while( z<zEnd ){
349
+ if(*z==0){
350
+ ++z;
351
+ continue;
352
+ }
353
+ else if('\n'==*z){
354
+ if(2==tokenizerState){
355
+ /* We were expecting a value for a successful match
356
+ here, but got no value. Bail out. */
357
+ break;
358
+ }else{
359
+ /* May happen on malformed inputs. Skip this record. */
360
+ tokenizerState = 0;
361
+ ++z;
362
+ continue;
363
+ }
364
+ }
365
+ switch(tokenizerState){
366
+ case 0:{ /* This is a file extension */
367
+ static char * zCase = 0;
368
+ if('.'==*z){
369
+ /*ignore an optional leading dot, for compatibility
370
+ with some external mimetype lists*/;
371
+ if(++z==zEnd){
372
+ break;
373
+ }
374
+ }
375
+ if(zCase<z){
376
+ /*we have not yet case-folded this section: lower-case it*/
377
+ for(zCase = z; zCase<zEnd && *zCase!=0; ++zCase){
378
+ if(!(0x80 & *zCase)){
379
+ *zCase = (char)fossil_tolower(*zCase);
380
+ }
381
+ }
382
+ }
383
+ if(strcmp(z,zSuffix)==0){
384
+ tokenizerState = 2 /* Match: accept the next value. */;
385
+ }else{
386
+ tokenizerState = 1 /* No match: skip the next value. */;
387
+ }
388
+ z += strlen(z);
389
+ break;
390
+ }
391
+ case 1: /* This is a value, but not a match. Skip it. */
392
+ z += strlen(z);
393
+ break;
394
+ case 2: /* This is the value which matched the previous key. */;
395
+ return z;
396
+ default:
397
+ assert(!"cannot happen - invalid tokenizerState value.");
398
+ }
399
+ }
400
+ return 0;
401
+}
309402
310403
/*
311404
** Guess the mime-type of a document based on its name.
312405
*/
313406
const char *mimetype_from_name(const char *zName){
@@ -334,10 +427,14 @@
334427
}
335428
len = strlen(z);
336429
if( len<sizeof(zSuffix)-1 ){
337430
sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
338431
for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
432
+ z = mimetype_from_name_custom(zSuffix);
433
+ if(z!=0){
434
+ return z;
435
+ }
339436
first = 0;
340437
last = count(aMime) - 1;
341438
while( first<=last ){
342439
int c;
343440
i = (first+last)/2;
@@ -365,10 +462,11 @@
365462
** It should return "ok".
366463
*/
367464
void mimetype_test_cmd(void){
368465
int i;
369466
mimetype_verify();
467
+ db_find_and_open_repository(0, 0);
370468
for(i=2; i<g.argc; i++){
371469
fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
372470
}
373471
}
374472
@@ -378,23 +476,67 @@
378476
** Show the built-in table used to guess embedded document mimetypes
379477
** from file suffixes.
380478
*/
381479
void mimetype_list_page(void){
382480
int i;
481
+ char *zCustomList = 0; /* value of the mimetypes setting */
482
+ int nCustomEntries = 0; /* number of entries in the mimetypes
483
+ ** setting */
383484
mimetype_verify();
384485
style_header("Mimetype List");
385486
@ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
386
- @ suffixes and the following table to guess at the appropriate mimetype
387
- @ for each document.</p>
487
+ @ suffixes and the following tables to guess at the appropriate mimetype
488
+ @ for each document. Mimetypes may be customized and overridden using
489
+ @ <a href="%R/help?cmd=mimetypes">the mimetypes config setting</a>.</p>
490
+ zCustomList = db_get("mimetypes",0);
491
+ if( zCustomList!=0 ){
492
+ Blob list, entry, key, val;
493
+ @ <h1>Repository-specific mimetypes</h1>
494
+ @ <p>The following extension-to-mimetype mappings are defined via
495
+ @ the <a href="%R/help?cmd=mimetypes">mimetypes setting</a>.</p>
496
+ @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
497
+ @ data-column-types='tt' data-init-sort='0'>
498
+ @ <thead>
499
+ @ <tr><th>Suffix<th>Mimetype
500
+ @ </thead>
501
+ @ <tbody>
502
+ blob_set(&list, zCustomList);
503
+ while( blob_line(&list, &entry)>0 ){
504
+ const char *zKey;
505
+ if( blob_token(&entry, &key)==0 ) continue;
506
+ if( blob_token(&entry, &val)==0 ) continue;
507
+ zKey = blob_str(&key);
508
+ if( zKey[0]=='.' ) zKey++;
509
+ @ <tr><td>%h(zKey)<td>%h(blob_str(&val))</tr>
510
+ nCustomEntries++;
511
+ }
512
+ fossil_free(zCustomList);
513
+ if( nCustomEntries==0 ){
514
+ /* This can happen if the option is set to an empty/space-only
515
+ ** value. */
516
+ @ <tr><td colspan="2"><em>none</em></tr>
517
+ }
518
+ @ </tbody></table>
519
+ }
520
+ @ <h1>Default built-in mimetypes</h1>
521
+ if(nCustomEntries>0){
522
+ @ <p>Entries starting with an exclamation mark <em><strong>!</strong></em>
523
+ @ are overwritten by repository-specific settings.</p>
524
+ }
388525
@ <table class='sortable mimetypetable' border=1 cellpadding=0 \
389526
@ data-column-types='tt' data-init-sort='1'>
390527
@ <thead>
391528
@ <tr><th>Suffix<th>Mimetype
392529
@ </thead>
393530
@ <tbody>
394531
for(i=0; i<count(aMime); i++){
395
- @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
532
+ const char *zFlag = "";
533
+ if(nCustomEntries>0 &&
534
+ mimetype_from_name_custom(aMime[i].zSuffix)!=0){
535
+ zFlag = "<em><strong>!</strong></em> ";
536
+ }
537
+ @ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
396538
}
397539
@ </tbody></table>
398540
style_table_sorter();
399541
style_footer();
400542
}
401543
--- src/doc.c
+++ src/doc.c
@@ -304,10 +304,103 @@
304 fossil_panic("mimetypes out of sequence: %s before %s",
305 aMime[i-1].zSuffix, aMime[i].zSuffix);
306 }
307 }
308 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
310 /*
311 ** Guess the mime-type of a document based on its name.
312 */
313 const char *mimetype_from_name(const char *zName){
@@ -334,10 +427,14 @@
334 }
335 len = strlen(z);
336 if( len<sizeof(zSuffix)-1 ){
337 sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
338 for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
 
 
 
 
339 first = 0;
340 last = count(aMime) - 1;
341 while( first<=last ){
342 int c;
343 i = (first+last)/2;
@@ -365,10 +462,11 @@
365 ** It should return "ok".
366 */
367 void mimetype_test_cmd(void){
368 int i;
369 mimetype_verify();
 
370 for(i=2; i<g.argc; i++){
371 fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
372 }
373 }
374
@@ -378,23 +476,67 @@
378 ** Show the built-in table used to guess embedded document mimetypes
379 ** from file suffixes.
380 */
381 void mimetype_list_page(void){
382 int i;
 
 
 
383 mimetype_verify();
384 style_header("Mimetype List");
385 @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
386 @ suffixes and the following table to guess at the appropriate mimetype
387 @ for each document.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388 @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
389 @ data-column-types='tt' data-init-sort='1'>
390 @ <thead>
391 @ <tr><th>Suffix<th>Mimetype
392 @ </thead>
393 @ <tbody>
394 for(i=0; i<count(aMime); i++){
395 @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
 
 
 
 
 
396 }
397 @ </tbody></table>
398 style_table_sorter();
399 style_footer();
400 }
401
--- src/doc.c
+++ src/doc.c
@@ -304,10 +304,103 @@
304 fossil_panic("mimetypes out of sequence: %s before %s",
305 aMime[i-1].zSuffix, aMime[i].zSuffix);
306 }
307 }
308 }
309
310 /*
311 ** Looks in the contents of the "mimetypes" setting for a suffix
312 ** matching zSuffix. If found, it returns the configured value
313 ** in memory owned by the app (i.e. do not free() it), else it
314 ** returns 0.
315 **
316 ** The mimetypes setting is expected to be a list of file extensions
317 ** and mimetypes, with one such mapping per line. A leading '.' on
318 ** extensions is permitted for compatibility with lists imported from
319 ** other tools which require them.
320 */
321 static const char *mimetype_from_name_custom(const char *zSuffix){
322 static char * zList = 0;
323 static char const * zEnd = 0;
324 static int once = 0;
325 char * z;
326 int tokenizerState /* 0=expecting a key, 1=skip next token,
327 ** 2=accept next token */;
328 if(once==0){
329 once = 1;
330 zList = db_get("mimetypes",0);
331 if(zList==0){
332 return 0;
333 }
334 /* Transform zList to simplify the main loop:
335 replace non-newline spaces with NUL bytes. */
336 zEnd = zList + strlen(zList);
337 for(z = zList; z<zEnd; ++z){
338 if('\n'==*z) continue;
339 else if(fossil_isspace(*z)){
340 *z = 0;
341 }
342 }
343 }else if(zList==0){
344 return 0;
345 }
346 tokenizerState = 0;
347 z = zList;
348 while( z<zEnd ){
349 if(*z==0){
350 ++z;
351 continue;
352 }
353 else if('\n'==*z){
354 if(2==tokenizerState){
355 /* We were expecting a value for a successful match
356 here, but got no value. Bail out. */
357 break;
358 }else{
359 /* May happen on malformed inputs. Skip this record. */
360 tokenizerState = 0;
361 ++z;
362 continue;
363 }
364 }
365 switch(tokenizerState){
366 case 0:{ /* This is a file extension */
367 static char * zCase = 0;
368 if('.'==*z){
369 /*ignore an optional leading dot, for compatibility
370 with some external mimetype lists*/;
371 if(++z==zEnd){
372 break;
373 }
374 }
375 if(zCase<z){
376 /*we have not yet case-folded this section: lower-case it*/
377 for(zCase = z; zCase<zEnd && *zCase!=0; ++zCase){
378 if(!(0x80 & *zCase)){
379 *zCase = (char)fossil_tolower(*zCase);
380 }
381 }
382 }
383 if(strcmp(z,zSuffix)==0){
384 tokenizerState = 2 /* Match: accept the next value. */;
385 }else{
386 tokenizerState = 1 /* No match: skip the next value. */;
387 }
388 z += strlen(z);
389 break;
390 }
391 case 1: /* This is a value, but not a match. Skip it. */
392 z += strlen(z);
393 break;
394 case 2: /* This is the value which matched the previous key. */;
395 return z;
396 default:
397 assert(!"cannot happen - invalid tokenizerState value.");
398 }
399 }
400 return 0;
401 }
402
403 /*
404 ** Guess the mime-type of a document based on its name.
405 */
406 const char *mimetype_from_name(const char *zName){
@@ -334,10 +427,14 @@
427 }
428 len = strlen(z);
429 if( len<sizeof(zSuffix)-1 ){
430 sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
431 for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
432 z = mimetype_from_name_custom(zSuffix);
433 if(z!=0){
434 return z;
435 }
436 first = 0;
437 last = count(aMime) - 1;
438 while( first<=last ){
439 int c;
440 i = (first+last)/2;
@@ -365,10 +462,11 @@
462 ** It should return "ok".
463 */
464 void mimetype_test_cmd(void){
465 int i;
466 mimetype_verify();
467 db_find_and_open_repository(0, 0);
468 for(i=2; i<g.argc; i++){
469 fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
470 }
471 }
472
@@ -378,23 +476,67 @@
476 ** Show the built-in table used to guess embedded document mimetypes
477 ** from file suffixes.
478 */
479 void mimetype_list_page(void){
480 int i;
481 char *zCustomList = 0; /* value of the mimetypes setting */
482 int nCustomEntries = 0; /* number of entries in the mimetypes
483 ** setting */
484 mimetype_verify();
485 style_header("Mimetype List");
486 @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
487 @ suffixes and the following tables to guess at the appropriate mimetype
488 @ for each document. Mimetypes may be customized and overridden using
489 @ <a href="%R/help?cmd=mimetypes">the mimetypes config setting</a>.</p>
490 zCustomList = db_get("mimetypes",0);
491 if( zCustomList!=0 ){
492 Blob list, entry, key, val;
493 @ <h1>Repository-specific mimetypes</h1>
494 @ <p>The following extension-to-mimetype mappings are defined via
495 @ the <a href="%R/help?cmd=mimetypes">mimetypes setting</a>.</p>
496 @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
497 @ data-column-types='tt' data-init-sort='0'>
498 @ <thead>
499 @ <tr><th>Suffix<th>Mimetype
500 @ </thead>
501 @ <tbody>
502 blob_set(&list, zCustomList);
503 while( blob_line(&list, &entry)>0 ){
504 const char *zKey;
505 if( blob_token(&entry, &key)==0 ) continue;
506 if( blob_token(&entry, &val)==0 ) continue;
507 zKey = blob_str(&key);
508 if( zKey[0]=='.' ) zKey++;
509 @ <tr><td>%h(zKey)<td>%h(blob_str(&val))</tr>
510 nCustomEntries++;
511 }
512 fossil_free(zCustomList);
513 if( nCustomEntries==0 ){
514 /* This can happen if the option is set to an empty/space-only
515 ** value. */
516 @ <tr><td colspan="2"><em>none</em></tr>
517 }
518 @ </tbody></table>
519 }
520 @ <h1>Default built-in mimetypes</h1>
521 if(nCustomEntries>0){
522 @ <p>Entries starting with an exclamation mark <em><strong>!</strong></em>
523 @ are overwritten by repository-specific settings.</p>
524 }
525 @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
526 @ data-column-types='tt' data-init-sort='1'>
527 @ <thead>
528 @ <tr><th>Suffix<th>Mimetype
529 @ </thead>
530 @ <tbody>
531 for(i=0; i<count(aMime); i++){
532 const char *zFlag = "";
533 if(nCustomEntries>0 &&
534 mimetype_from_name_custom(aMime[i].zSuffix)!=0){
535 zFlag = "<em><strong>!</strong></em> ";
536 }
537 @ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
538 }
539 @ </tbody></table>
540 style_table_sorter();
541 style_footer();
542 }
543

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button