Fossil SCM

Added support for client-configurable mimetypes as a versionable setting.

stephan 2020-01-22 02:41 trunk
Commit 322643cac8465e9e62295a8ffa375b378677b09c3a962b1556352d1152599d15
2 files changed +5 +91 -1
+5
--- src/db.c
+++ src/db.c
@@ -3449,10 +3449,15 @@
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.
3457
+** Note that extensions are compared case-insensitively.
3458
+*/
34543459
/*
34553460
** SETTING: mtime-changes boolean default=on
34563461
** Use file modification times (mtimes) to detect when
34573462
** files have been modified. If disabled, all managed files
34583463
** are hashed to detect changes, which can be slow for large
34593464
--- src/db.c
+++ src/db.c
@@ -3449,10 +3449,15 @@
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,15 @@
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.
3457 ** Note that extensions are compared case-insensitively.
3458 */
3459 /*
3460 ** SETTING: mtime-changes boolean default=on
3461 ** Use file modification times (mtimes) to detect when
3462 ** files have been modified. If disabled, all managed files
3463 ** are hashed to detect changes, which can be slow for large
3464
+91 -1
--- src/doc.c
+++ src/doc.c
@@ -304,10 +304,83 @@
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
+static const char *mimetype_from_name_custom(const char *zSuffix){
317
+ static char * zList = 0;
318
+ static char const * zEnd = 0;
319
+ static int once = 0;
320
+ char * z;
321
+ int tokenizerState /* 0=expecting a key, 1=skip next token,
322
+ ** 2=accept next token */;
323
+ if(once==0){
324
+ once = 1;
325
+ zList = db_get("mimetypes",0);
326
+ if(zList==0){
327
+ return 0;
328
+ }
329
+ /* Initialize zList and transform it to simplify
330
+ the main loop. */
331
+ zEnd = zList + strlen(zList);
332
+ for(z = zList; z<zEnd; ++z){
333
+ if('\n'==*z) continue;
334
+ else if(fossil_isspace(*z)){
335
+ *z = 0;
336
+ }else if(!(0x80 & *z)){
337
+ *z = (char)fossil_tolower(*z);
338
+ }
339
+ }
340
+ }else if(zList==0){
341
+ return 0;
342
+ }
343
+ tokenizerState = 0;
344
+ z = zList;
345
+ while( z<zEnd ){
346
+ if(*z==0){
347
+ ++z;
348
+ continue;
349
+ }
350
+ else if('\n'==*z){
351
+ /* May happen on malformed inputs. Skip this record. */
352
+ if(2==tokenizerState){
353
+ /* We were expecting a value for a successful match
354
+ here, but got no value. Bail out. */
355
+ break;
356
+ }else{
357
+ tokenizerState = 0;
358
+ ++z;
359
+ continue;
360
+ }
361
+ }
362
+ switch(tokenizerState){
363
+ case 0: /* This is a file extension */
364
+ if(strcmp(z,zSuffix)==0){
365
+ tokenizerState = 2 /*Match: accept the next value. */;
366
+ }else{
367
+ tokenizerState = 1 /* No match: skip the next value */;
368
+ }
369
+ z += strlen(z);
370
+ break;
371
+ case 1: /* This is a value, but not a match. Skip it. */
372
+ z += strlen(z);
373
+ break;
374
+ case 2: /* This is the value which matched the previous key */;
375
+ return z;
376
+ default:
377
+ assert(!"cannot happen - invalid tokenizerState value.");
378
+ }
379
+ }
380
+ return 0;
381
+}
309382
310383
/*
311384
** Guess the mime-type of a document based on its name.
312385
*/
313386
const char *mimetype_from_name(const char *zName){
@@ -333,10 +406,14 @@
333406
if( zName[i]=='.' ) z = &zName[i+1];
334407
}
335408
len = strlen(z);
336409
if( len<sizeof(zSuffix)-1 ){
337410
sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
411
+ z = mimetype_from_name_custom(zSuffix);
412
+ if(z!=0){
413
+ return z;
414
+ }
338415
for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
339416
first = 0;
340417
last = count(aMime) - 1;
341418
while( first<=last ){
342419
int c;
@@ -365,10 +442,11 @@
365442
** It should return "ok".
366443
*/
367444
void mimetype_test_cmd(void){
368445
int i;
369446
mimetype_verify();
447
+ db_find_and_open_repository(0, 0);
370448
for(i=2; i<g.argc; i++){
371449
fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
372450
}
373451
}
374452
@@ -378,10 +456,11 @@
378456
** Show the built-in table used to guess embedded document mimetypes
379457
** from file suffixes.
380458
*/
381459
void mimetype_list_page(void){
382460
int i;
461
+ char * zCustomList = 0;
383462
mimetype_verify();
384463
style_header("Mimetype List");
385464
@ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
386465
@ suffixes and the following table to guess at the appropriate mimetype
387466
@ for each document.</p>
@@ -393,11 +472,22 @@
393472
@ <tbody>
394473
for(i=0; i<count(aMime); i++){
395474
@ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
396475
}
397476
@ </tbody></table>
398
- style_table_sorter();
477
+ zCustomList = db_get("mimetypes",0);
478
+ if(zCustomList!=0){
479
+ /* TODO: render this as a table, rather than a TEXTAREA. That
480
+ ** requires tokenizing the input, though, duplicating much of the
481
+ ** work done in mimetype_from_name_custom().
482
+ */
483
+ @ <h1>Repo-specific mimetypes</h1>
484
+ @ The following extention-to-mimetype mappings are defined via the
485
+ @ <a href="%R/help?cmd=mimetypes">mimetypes setting</a>:<br>
486
+ @ <textarea rows='10' cols='40' readonly>%s(zCustomList)</textarea>
487
+ fossil_free(zCustomList);
488
+ }
399489
style_footer();
400490
}
401491
402492
/*
403493
** Check to see if the file in the pContent blob is "embedded HTML". Return
404494
--- src/doc.c
+++ src/doc.c
@@ -304,10 +304,83 @@
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){
@@ -333,10 +406,14 @@
333 if( zName[i]=='.' ) z = &zName[i+1];
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;
@@ -365,10 +442,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,10 +456,11 @@
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>
@@ -393,11 +472,22 @@
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
402 /*
403 ** Check to see if the file in the pContent blob is "embedded HTML". Return
404
--- src/doc.c
+++ src/doc.c
@@ -304,10 +304,83 @@
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 static const char *mimetype_from_name_custom(const char *zSuffix){
317 static char * zList = 0;
318 static char const * zEnd = 0;
319 static int once = 0;
320 char * z;
321 int tokenizerState /* 0=expecting a key, 1=skip next token,
322 ** 2=accept next token */;
323 if(once==0){
324 once = 1;
325 zList = db_get("mimetypes",0);
326 if(zList==0){
327 return 0;
328 }
329 /* Initialize zList and transform it to simplify
330 the main loop. */
331 zEnd = zList + strlen(zList);
332 for(z = zList; z<zEnd; ++z){
333 if('\n'==*z) continue;
334 else if(fossil_isspace(*z)){
335 *z = 0;
336 }else if(!(0x80 & *z)){
337 *z = (char)fossil_tolower(*z);
338 }
339 }
340 }else if(zList==0){
341 return 0;
342 }
343 tokenizerState = 0;
344 z = zList;
345 while( z<zEnd ){
346 if(*z==0){
347 ++z;
348 continue;
349 }
350 else if('\n'==*z){
351 /* May happen on malformed inputs. Skip this record. */
352 if(2==tokenizerState){
353 /* We were expecting a value for a successful match
354 here, but got no value. Bail out. */
355 break;
356 }else{
357 tokenizerState = 0;
358 ++z;
359 continue;
360 }
361 }
362 switch(tokenizerState){
363 case 0: /* This is a file extension */
364 if(strcmp(z,zSuffix)==0){
365 tokenizerState = 2 /*Match: accept the next value. */;
366 }else{
367 tokenizerState = 1 /* No match: skip the next value */;
368 }
369 z += strlen(z);
370 break;
371 case 1: /* This is a value, but not a match. Skip it. */
372 z += strlen(z);
373 break;
374 case 2: /* This is the value which matched the previous key */;
375 return z;
376 default:
377 assert(!"cannot happen - invalid tokenizerState value.");
378 }
379 }
380 return 0;
381 }
382
383 /*
384 ** Guess the mime-type of a document based on its name.
385 */
386 const char *mimetype_from_name(const char *zName){
@@ -333,10 +406,14 @@
406 if( zName[i]=='.' ) z = &zName[i+1];
407 }
408 len = strlen(z);
409 if( len<sizeof(zSuffix)-1 ){
410 sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
411 z = mimetype_from_name_custom(zSuffix);
412 if(z!=0){
413 return z;
414 }
415 for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
416 first = 0;
417 last = count(aMime) - 1;
418 while( first<=last ){
419 int c;
@@ -365,10 +442,11 @@
442 ** It should return "ok".
443 */
444 void mimetype_test_cmd(void){
445 int i;
446 mimetype_verify();
447 db_find_and_open_repository(0, 0);
448 for(i=2; i<g.argc; i++){
449 fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
450 }
451 }
452
@@ -378,10 +456,11 @@
456 ** Show the built-in table used to guess embedded document mimetypes
457 ** from file suffixes.
458 */
459 void mimetype_list_page(void){
460 int i;
461 char * zCustomList = 0;
462 mimetype_verify();
463 style_header("Mimetype List");
464 @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
465 @ suffixes and the following table to guess at the appropriate mimetype
466 @ for each document.</p>
@@ -393,11 +472,22 @@
472 @ <tbody>
473 for(i=0; i<count(aMime); i++){
474 @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
475 }
476 @ </tbody></table>
477 zCustomList = db_get("mimetypes",0);
478 if(zCustomList!=0){
479 /* TODO: render this as a table, rather than a TEXTAREA. That
480 ** requires tokenizing the input, though, duplicating much of the
481 ** work done in mimetype_from_name_custom().
482 */
483 @ <h1>Repo-specific mimetypes</h1>
484 @ The following extention-to-mimetype mappings are defined via the
485 @ <a href="%R/help?cmd=mimetypes">mimetypes setting</a>:<br>
486 @ <textarea rows='10' cols='40' readonly>%s(zCustomList)</textarea>
487 fossil_free(zCustomList);
488 }
489 style_footer();
490 }
491
492 /*
493 ** Check to see if the file in the pContent blob is "embedded HTML". Return
494

Keyboard Shortcuts

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