Fossil SCM

Add the /juvlist webpage that returns a list of all unversioned files as JSON.

drh 2017-03-04 14:29 trunk
Commit 7d12ba544f7ecc192ed1b4a7fb81b671b4939c9f
+1 -1
--- src/doc.c
+++ src/doc.c
@@ -735,11 +735,11 @@
735735
736736
/* Jump here when unable to locate the document */
737737
doc_not_found:
738738
db_end_transaction(0);
739739
if( isUV && P("name")==0 ){
740
- uvstat_page();
740
+ uvlist_page();
741741
return;
742742
}
743743
cgi_set_status(404, "Not Found");
744744
style_header("Not Found");
745745
@ <p>Document %h(zOrigName) not found
746746
--- src/doc.c
+++ src/doc.c
@@ -735,11 +735,11 @@
735
736 /* Jump here when unable to locate the document */
737 doc_not_found:
738 db_end_transaction(0);
739 if( isUV && P("name")==0 ){
740 uvstat_page();
741 return;
742 }
743 cgi_set_status(404, "Not Found");
744 style_header("Not Found");
745 @ <p>Document %h(zOrigName) not found
746
--- src/doc.c
+++ src/doc.c
@@ -735,11 +735,11 @@
735
736 /* Jump here when unable to locate the document */
737 doc_not_found:
738 db_end_transaction(0);
739 if( isUV && P("name")==0 ){
740 uvlist_page();
741 return;
742 }
743 cgi_set_status(404, "Not Found");
744 style_header("Not Found");
745 @ <p>Document %h(zOrigName) not found
746
+90
--- src/encode.c
+++ src/encode.c
@@ -336,10 +336,100 @@
336336
z[j++] = c;
337337
}
338338
if( z[j] ) z[j] = 0;
339339
}
340340
341
+
342
+/*
343
+** The *pz variable points to a UTF8 string. Read the next character
344
+** off of that string and return its codepoint value. Advance *pz to the
345
+** next character
346
+*/
347
+u32 fossil_utf8_read(
348
+ const unsigned char **pz /* Pointer to string from which to read char */
349
+){
350
+ unsigned int c;
351
+
352
+ /*
353
+ ** This lookup table is used to help decode the first byte of
354
+ ** a multi-byte UTF8 character.
355
+ */
356
+ static const unsigned char utf8Trans1[] = {
357
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
358
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
359
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
360
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
361
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
362
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
363
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
364
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
365
+ };
366
+
367
+ c = *((*pz)++);
368
+ if( c>=0xc0 ){
369
+ c = utf8Trans1[c-0xc0];
370
+ while( (*(*pz) & 0xc0)==0x80 ){
371
+ c = (c<<6) + (0x3f & *((*pz)++));
372
+ }
373
+ if( c<0x80
374
+ || (c&0xFFFFF800)==0xD800
375
+ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
376
+ }
377
+ return c;
378
+}
379
+
380
+/*
381
+** Encode a UTF8 string for JSON. All special characters are escaped.
382
+*/
383
+void blob_append_json_string(Blob *pBlob, const char *zStr){
384
+ const unsigned char *z;
385
+ char *zOut;
386
+ u32 c;
387
+ int n, i, j;
388
+ z = (const unsigned char*)zStr;
389
+ n = 0;
390
+ while( (c = fossil_utf8_read(&z))!=0 ){
391
+ if( c=='\\' || c=='"' ){
392
+ n += 2;
393
+ }else if( c<' ' || c>=0x7f ){
394
+ if( c=='\n' || c=='\r' ){
395
+ n += 2;
396
+ }else{
397
+ n += 6;
398
+ }
399
+ }else{
400
+ n++;
401
+ }
402
+ }
403
+ i = blob_size(pBlob);
404
+ blob_resize(pBlob, i+n);
405
+ zOut = blob_buffer(pBlob);
406
+ z = (const unsigned char*)zStr;
407
+ while( (c = fossil_utf8_read(&z))!=0 ){
408
+ if( c=='\\' ){
409
+ zOut[i++] = '\\';
410
+ zOut[i++] = c;
411
+ }else if( c<' ' || c>=0x7f ){
412
+ zOut[i++] = '\\';
413
+ if( c=='\n' ){
414
+ zOut[i++] = 'n';
415
+ }else if( c=='\r' ){
416
+ zOut[i++] = 'r';
417
+ }else{
418
+ zOut[i++] = 'u';
419
+ for(j=3; j>=0; j--){
420
+ zOut[i+j] = "0123456789abcdef"[c&0xf];
421
+ c >>= 4;
422
+ }
423
+ i += 4;
424
+ }
425
+ }else{
426
+ zOut[i++] = c;
427
+ }
428
+ }
429
+ zOut[i] = 0;
430
+}
341431
342432
/*
343433
** The characters used for HTTP base64 encoding.
344434
*/
345435
static unsigned char zBase[] =
346436
--- src/encode.c
+++ src/encode.c
@@ -336,10 +336,100 @@
336 z[j++] = c;
337 }
338 if( z[j] ) z[j] = 0;
339 }
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
342 /*
343 ** The characters used for HTTP base64 encoding.
344 */
345 static unsigned char zBase[] =
346
--- src/encode.c
+++ src/encode.c
@@ -336,10 +336,100 @@
336 z[j++] = c;
337 }
338 if( z[j] ) z[j] = 0;
339 }
340
341
342 /*
343 ** The *pz variable points to a UTF8 string. Read the next character
344 ** off of that string and return its codepoint value. Advance *pz to the
345 ** next character
346 */
347 u32 fossil_utf8_read(
348 const unsigned char **pz /* Pointer to string from which to read char */
349 ){
350 unsigned int c;
351
352 /*
353 ** This lookup table is used to help decode the first byte of
354 ** a multi-byte UTF8 character.
355 */
356 static const unsigned char utf8Trans1[] = {
357 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
358 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
359 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
360 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
361 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
362 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
363 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
364 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
365 };
366
367 c = *((*pz)++);
368 if( c>=0xc0 ){
369 c = utf8Trans1[c-0xc0];
370 while( (*(*pz) & 0xc0)==0x80 ){
371 c = (c<<6) + (0x3f & *((*pz)++));
372 }
373 if( c<0x80
374 || (c&0xFFFFF800)==0xD800
375 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
376 }
377 return c;
378 }
379
380 /*
381 ** Encode a UTF8 string for JSON. All special characters are escaped.
382 */
383 void blob_append_json_string(Blob *pBlob, const char *zStr){
384 const unsigned char *z;
385 char *zOut;
386 u32 c;
387 int n, i, j;
388 z = (const unsigned char*)zStr;
389 n = 0;
390 while( (c = fossil_utf8_read(&z))!=0 ){
391 if( c=='\\' || c=='"' ){
392 n += 2;
393 }else if( c<' ' || c>=0x7f ){
394 if( c=='\n' || c=='\r' ){
395 n += 2;
396 }else{
397 n += 6;
398 }
399 }else{
400 n++;
401 }
402 }
403 i = blob_size(pBlob);
404 blob_resize(pBlob, i+n);
405 zOut = blob_buffer(pBlob);
406 z = (const unsigned char*)zStr;
407 while( (c = fossil_utf8_read(&z))!=0 ){
408 if( c=='\\' ){
409 zOut[i++] = '\\';
410 zOut[i++] = c;
411 }else if( c<' ' || c>=0x7f ){
412 zOut[i++] = '\\';
413 if( c=='\n' ){
414 zOut[i++] = 'n';
415 }else if( c=='\r' ){
416 zOut[i++] = 'r';
417 }else{
418 zOut[i++] = 'u';
419 for(j=3; j>=0; j--){
420 zOut[i+j] = "0123456789abcdef"[c&0xf];
421 c >>= 4;
422 }
423 i += 4;
424 }
425 }else{
426 zOut[i++] = c;
427 }
428 }
429 zOut[i] = 0;
430 }
431
432 /*
433 ** The characters used for HTTP base64 encoding.
434 */
435 static unsigned char zBase[] =
436
--- src/unversioned.c
+++ src/unversioned.c
@@ -456,11 +456,11 @@
456456
** Query parameters:
457457
**
458458
** byage=1 Order the initial display be decreasing age
459459
** showdel=0 Show deleted files
460460
*/
461
-void uvstat_page(void){
461
+void uvlist_page(void){
462462
Stmt q;
463463
sqlite3_int64 iNow;
464464
sqlite3_int64 iTotalSz = 0;
465465
int cnt = 0;
466466
int n = 0;
@@ -554,5 +554,62 @@
554554
}else{
555555
@ No unversioned files on this server.
556556
}
557557
style_footer();
558558
}
559
+
560
+/*
561
+** WEBPAGE: juvlist
562
+**
563
+** Return a complete list of unversioned files as JSON. The JSON
564
+** looks like this:
565
+**
566
+** [{"name":NAME,
567
+** "mtime":MTIME,
568
+** "hash":HASH,
569
+** "size":SIZE,
570
+* "user":USER}]
571
+*/
572
+void uvlist_json_page(void){
573
+ Stmt q;
574
+ char *zSep = "[";
575
+ Blob json;
576
+
577
+ login_check_credentials();
578
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
579
+ cgi_set_content_type("text/json");
580
+ if( !db_table_exists("repository","unversioned") ){
581
+ blob_init(&json, "[]", -1);
582
+ cgi_set_content(&json);
583
+ return;
584
+ }
585
+ blob_init(&json, 0, 0);
586
+ db_prepare(&q,
587
+ "SELECT"
588
+ " name,"
589
+ " mtime,"
590
+ " hash,"
591
+ " sz,"
592
+ " (SELECT login FROM rcvfrom, user"
593
+ " WHERE user.uid=rcvfrom.uid AND rcvfrom.rcvid=unversioned.rcvid)"
594
+ " FROM unversioned WHERE hash IS NOT NULL"
595
+ );
596
+ while( db_step(&q)==SQLITE_ROW ){
597
+ const char *zName = db_column_text(&q, 0);
598
+ sqlite3_int64 mtime = db_column_int(&q, 1);
599
+ const char *zHash = db_column_text(&q, 2);
600
+ int fullSize = db_column_int(&q, 3);
601
+ const char *zLogin = db_column_text(&q, 4);
602
+ if( zLogin==0 ) zLogin = "";
603
+ blob_appendf(&json, "%s{\"name\":\"", zSep);
604
+ zSep = ",\n ";
605
+ blob_append_json_string(&json, zName);
606
+ blob_appendf(&json, "\",\n \"mtime\":%lld,\n \"hash\":\"", mtime);
607
+ blob_append_json_string(&json, zHash);
608
+ blob_appendf(&json, "\",\n \"size\":%d,\n \"user\":\"", fullSize);
609
+ blob_append_json_string(&json, zLogin);
610
+ blob_appendf(&json, "\"}");
611
+ }
612
+ db_finalize(&q);
613
+ blob_appendf(&json,"]\n");
614
+ cgi_set_content(&json);
615
+}
559616
--- src/unversioned.c
+++ src/unversioned.c
@@ -456,11 +456,11 @@
456 ** Query parameters:
457 **
458 ** byage=1 Order the initial display be decreasing age
459 ** showdel=0 Show deleted files
460 */
461 void uvstat_page(void){
462 Stmt q;
463 sqlite3_int64 iNow;
464 sqlite3_int64 iTotalSz = 0;
465 int cnt = 0;
466 int n = 0;
@@ -554,5 +554,62 @@
554 }else{
555 @ No unversioned files on this server.
556 }
557 style_footer();
558 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
--- src/unversioned.c
+++ src/unversioned.c
@@ -456,11 +456,11 @@
456 ** Query parameters:
457 **
458 ** byage=1 Order the initial display be decreasing age
459 ** showdel=0 Show deleted files
460 */
461 void uvlist_page(void){
462 Stmt q;
463 sqlite3_int64 iNow;
464 sqlite3_int64 iTotalSz = 0;
465 int cnt = 0;
466 int n = 0;
@@ -554,5 +554,62 @@
554 }else{
555 @ No unversioned files on this server.
556 }
557 style_footer();
558 }
559
560 /*
561 ** WEBPAGE: juvlist
562 **
563 ** Return a complete list of unversioned files as JSON. The JSON
564 ** looks like this:
565 **
566 ** [{"name":NAME,
567 ** "mtime":MTIME,
568 ** "hash":HASH,
569 ** "size":SIZE,
570 * "user":USER}]
571 */
572 void uvlist_json_page(void){
573 Stmt q;
574 char *zSep = "[";
575 Blob json;
576
577 login_check_credentials();
578 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
579 cgi_set_content_type("text/json");
580 if( !db_table_exists("repository","unversioned") ){
581 blob_init(&json, "[]", -1);
582 cgi_set_content(&json);
583 return;
584 }
585 blob_init(&json, 0, 0);
586 db_prepare(&q,
587 "SELECT"
588 " name,"
589 " mtime,"
590 " hash,"
591 " sz,"
592 " (SELECT login FROM rcvfrom, user"
593 " WHERE user.uid=rcvfrom.uid AND rcvfrom.rcvid=unversioned.rcvid)"
594 " FROM unversioned WHERE hash IS NOT NULL"
595 );
596 while( db_step(&q)==SQLITE_ROW ){
597 const char *zName = db_column_text(&q, 0);
598 sqlite3_int64 mtime = db_column_int(&q, 1);
599 const char *zHash = db_column_text(&q, 2);
600 int fullSize = db_column_int(&q, 3);
601 const char *zLogin = db_column_text(&q, 4);
602 if( zLogin==0 ) zLogin = "";
603 blob_appendf(&json, "%s{\"name\":\"", zSep);
604 zSep = ",\n ";
605 blob_append_json_string(&json, zName);
606 blob_appendf(&json, "\",\n \"mtime\":%lld,\n \"hash\":\"", mtime);
607 blob_append_json_string(&json, zHash);
608 blob_appendf(&json, "\",\n \"size\":%d,\n \"user\":\"", fullSize);
609 blob_append_json_string(&json, zLogin);
610 blob_appendf(&json, "\"}");
611 }
612 db_finalize(&q);
613 blob_appendf(&json,"]\n");
614 cgi_set_content(&json);
615 }
616

Keyboard Shortcuts

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