Fossil SCM
added command: wiki [export WikiName|list]
Commit
5fb1152dab8160e5fd690c4d7e234dfacb03d1b7
Parent
0a14f18111c9ea0…
1 file changed
+146
+146
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -22,10 +22,11 @@ | ||
| 22 | 22 | ******************************************************************************* |
| 23 | 23 | ** |
| 24 | 24 | ** This file contains code to do formatting of wiki text. |
| 25 | 25 | */ |
| 26 | 26 | #include <assert.h> |
| 27 | +#include <ctype.h> | |
| 27 | 28 | #include "config.h" |
| 28 | 29 | #include "wiki.h" |
| 29 | 30 | |
| 30 | 31 | /* |
| 31 | 32 | ** Return true if the input string is a well-formed wiki page name. |
| @@ -596,5 +597,150 @@ | ||
| 596 | 597 | @ disables all wiki formatting rules through the matching |
| 597 | 598 | @ </nowiki> element. |
| 598 | 599 | @ </ol> |
| 599 | 600 | style_footer(); |
| 600 | 601 | } |
| 602 | + | |
| 603 | +void dump_blob_to_FILE( Blob * b, FILE * f ) | |
| 604 | +{ | |
| 605 | + fwrite(blob_buffer(b), 1, blob_size(b), stdout); | |
| 606 | +} | |
| 607 | + | |
| 608 | +/* | |
| 609 | +** COMMAND: wiki | |
| 610 | +** | |
| 611 | +** Usage: %fossil wiki (export|import) EntryName | |
| 612 | +** | |
| 613 | +** | |
| 614 | +** TODOS: | |
| 615 | +** | |
| 616 | +** export WikiName ?UUID? ?-f outfile? | |
| 617 | +*/ | |
| 618 | +void wiki_cmd(void){ | |
| 619 | + int n; | |
| 620 | + db_find_and_open_repository(1); | |
| 621 | + if( g.argc<3 ){ | |
| 622 | + goto wiki_cmd_usage; | |
| 623 | + } | |
| 624 | + n = strlen(g.argv[2]); | |
| 625 | + if( n==0 ){ | |
| 626 | + goto wiki_cmd_usage; | |
| 627 | + } | |
| 628 | + | |
| 629 | + if( strncmp(g.argv[2],"export",n)==0 ){ | |
| 630 | + Stmt q; | |
| 631 | + char *wname; | |
| 632 | + Blob buf; | |
| 633 | + int rid; | |
| 634 | + char * sql; | |
| 635 | + if( g.argc!=4 ){ | |
| 636 | + usage("export EntryName"); | |
| 637 | + } | |
| 638 | + wname = g.argv[3]; | |
| 639 | + //printf("exporting wiki entry %s\n",wname); | |
| 640 | + rid = -1; | |
| 641 | + | |
| 642 | + sql = mprintf("select x.rid from tag t, tagxref x " | |
| 643 | + "where x.tagid=t.tagid and t.tagname='wiki-%q' " | |
| 644 | + " order by x.mtime desc limit 1", | |
| 645 | + wname ); | |
| 646 | + printf("SQL=%s\n",sql); | |
| 647 | + db_prepare(&q, "%z", sql ); | |
| 648 | + while( db_step(&q) == SQLITE_ROW ){ | |
| 649 | + rid = db_column_int(&q,0); | |
| 650 | + break; | |
| 651 | + } | |
| 652 | + db_finalize(&q); | |
| 653 | + if( -1 == rid ){ | |
| 654 | + fprintf(stderr,"export error: wiki entry [%s] not found.\n",wname); | |
| 655 | + exit(1); | |
| 656 | + } | |
| 657 | + fprintf(stderr,"export rid==%d\n", rid ); | |
| 658 | + if( ! content_get(rid,&buf) ){ | |
| 659 | + fprintf(stderr,"export error: content_get(%d) returned 0\n", rid ); | |
| 660 | + exit(1); | |
| 661 | + }else | |
| 662 | + { | |
| 663 | + /* Unfortunately, the content_get() routine does ALMOST what i want, | |
| 664 | + but not quite. It is quite complex, so i don't want to fork a | |
| 665 | + modified copy here. That's what all the skipping-over bits are for... | |
| 666 | + | |
| 667 | + We look for the first line starting with 'W', then expect ' | |
| 668 | + NUMBER\n' immediately after that, followed by NUMBER bytes | |
| 669 | + of plain blob content. | |
| 670 | + */ | |
| 671 | + int len; | |
| 672 | + char * it; | |
| 673 | + Blob numbuf; | |
| 674 | + blob_zero(&numbuf); | |
| 675 | + it = blob_buffer(&buf); | |
| 676 | + while(*it){ | |
| 677 | + if( *it != 'W' ){ | |
| 678 | + ++it; | |
| 679 | + while( *it ){ | |
| 680 | + if( *it == '\n') { ++it; break; } | |
| 681 | + ++it; | |
| 682 | + } | |
| 683 | + continue; | |
| 684 | + } | |
| 685 | + ++it; | |
| 686 | + while( (*it) && (*it != '\n') ){ | |
| 687 | + if( isspace(*it) ) { ++it; continue; } | |
| 688 | + blob_append(&numbuf,it,1); | |
| 689 | + ++it; | |
| 690 | + } | |
| 691 | + if( '\n' == *it ) ++it; | |
| 692 | + if( 0 == blob_size(&numbuf) ){ | |
| 693 | + fprintf(stderr, | |
| 694 | + "export error: didn't find \"W NUMBER\" line in input!\n"); | |
| 695 | + blob_zero(&buf); | |
| 696 | + blob_zero(&numbuf); | |
| 697 | + exit(1); | |
| 698 | + } | |
| 699 | + len = atoi(blob_buffer(&numbuf)); | |
| 700 | + //fprintf(stderr,"Writing %d (%s) bytes...\n",len,blob_buffer(&numbuf)); | |
| 701 | + blob_zero(&numbuf); | |
| 702 | + fwrite(it,sizeof(char),len,stdout); | |
| 703 | + blob_zero(&buf); | |
| 704 | + return; | |
| 705 | + } | |
| 706 | + } | |
| 707 | + blob_zero(&buf); | |
| 708 | + return; | |
| 709 | + }else | |
| 710 | + if( strncmp(g.argv[2],"import",n)==0 ){ | |
| 711 | + char *wname; | |
| 712 | + if( g.argc!=4 ){ | |
| 713 | + usage("import EntryName"); | |
| 714 | + } | |
| 715 | + wname = g.argv[3]; | |
| 716 | + fprintf(stderr,"import not yet implemented.\n"); | |
| 717 | + exit(1); | |
| 718 | + }else | |
| 719 | + if( strncmp(g.argv[2],"delete",n)==0 ){ | |
| 720 | + if( g.argc!=5 ){ | |
| 721 | + usage("delete WikiName"); | |
| 722 | + } | |
| 723 | + fprintf(stderr,"delete not yet implemented.\n"); | |
| 724 | + exit(1); | |
| 725 | + }else | |
| 726 | + if( strncmp(g.argv[2],"list",n)==0 ){ | |
| 727 | + Stmt q; | |
| 728 | + db_prepare(&q, | |
| 729 | + "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname GLOB 'wiki-*'" | |
| 730 | + " ORDER BY lower(tagname)" | |
| 731 | + ); | |
| 732 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 733 | + const char *zName = db_column_text(&q, 0); | |
| 734 | + printf( "%s\n",zName); | |
| 735 | + } | |
| 736 | + db_finalize(&q); | |
| 737 | + }else | |
| 738 | + { | |
| 739 | + goto wiki_cmd_usage; | |
| 740 | + } | |
| 741 | + return; | |
| 742 | + | |
| 743 | +wiki_cmd_usage: | |
| 744 | + usage("delete|export|import|list [EntryName]"); | |
| 745 | +} | |
| 746 | + | |
| 601 | 747 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -22,10 +22,11 @@ | |
| 22 | ******************************************************************************* |
| 23 | ** |
| 24 | ** This file contains code to do formatting of wiki text. |
| 25 | */ |
| 26 | #include <assert.h> |
| 27 | #include "config.h" |
| 28 | #include "wiki.h" |
| 29 | |
| 30 | /* |
| 31 | ** Return true if the input string is a well-formed wiki page name. |
| @@ -596,5 +597,150 @@ | |
| 596 | @ disables all wiki formatting rules through the matching |
| 597 | @ </nowiki> element. |
| 598 | @ </ol> |
| 599 | style_footer(); |
| 600 | } |
| 601 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -22,10 +22,11 @@ | |
| 22 | ******************************************************************************* |
| 23 | ** |
| 24 | ** This file contains code to do formatting of wiki text. |
| 25 | */ |
| 26 | #include <assert.h> |
| 27 | #include <ctype.h> |
| 28 | #include "config.h" |
| 29 | #include "wiki.h" |
| 30 | |
| 31 | /* |
| 32 | ** Return true if the input string is a well-formed wiki page name. |
| @@ -596,5 +597,150 @@ | |
| 597 | @ disables all wiki formatting rules through the matching |
| 598 | @ </nowiki> element. |
| 599 | @ </ol> |
| 600 | style_footer(); |
| 601 | } |
| 602 | |
| 603 | void dump_blob_to_FILE( Blob * b, FILE * f ) |
| 604 | { |
| 605 | fwrite(blob_buffer(b), 1, blob_size(b), stdout); |
| 606 | } |
| 607 | |
| 608 | /* |
| 609 | ** COMMAND: wiki |
| 610 | ** |
| 611 | ** Usage: %fossil wiki (export|import) EntryName |
| 612 | ** |
| 613 | ** |
| 614 | ** TODOS: |
| 615 | ** |
| 616 | ** export WikiName ?UUID? ?-f outfile? |
| 617 | */ |
| 618 | void wiki_cmd(void){ |
| 619 | int n; |
| 620 | db_find_and_open_repository(1); |
| 621 | if( g.argc<3 ){ |
| 622 | goto wiki_cmd_usage; |
| 623 | } |
| 624 | n = strlen(g.argv[2]); |
| 625 | if( n==0 ){ |
| 626 | goto wiki_cmd_usage; |
| 627 | } |
| 628 | |
| 629 | if( strncmp(g.argv[2],"export",n)==0 ){ |
| 630 | Stmt q; |
| 631 | char *wname; |
| 632 | Blob buf; |
| 633 | int rid; |
| 634 | char * sql; |
| 635 | if( g.argc!=4 ){ |
| 636 | usage("export EntryName"); |
| 637 | } |
| 638 | wname = g.argv[3]; |
| 639 | //printf("exporting wiki entry %s\n",wname); |
| 640 | rid = -1; |
| 641 | |
| 642 | sql = mprintf("select x.rid from tag t, tagxref x " |
| 643 | "where x.tagid=t.tagid and t.tagname='wiki-%q' " |
| 644 | " order by x.mtime desc limit 1", |
| 645 | wname ); |
| 646 | printf("SQL=%s\n",sql); |
| 647 | db_prepare(&q, "%z", sql ); |
| 648 | while( db_step(&q) == SQLITE_ROW ){ |
| 649 | rid = db_column_int(&q,0); |
| 650 | break; |
| 651 | } |
| 652 | db_finalize(&q); |
| 653 | if( -1 == rid ){ |
| 654 | fprintf(stderr,"export error: wiki entry [%s] not found.\n",wname); |
| 655 | exit(1); |
| 656 | } |
| 657 | fprintf(stderr,"export rid==%d\n", rid ); |
| 658 | if( ! content_get(rid,&buf) ){ |
| 659 | fprintf(stderr,"export error: content_get(%d) returned 0\n", rid ); |
| 660 | exit(1); |
| 661 | }else |
| 662 | { |
| 663 | /* Unfortunately, the content_get() routine does ALMOST what i want, |
| 664 | but not quite. It is quite complex, so i don't want to fork a |
| 665 | modified copy here. That's what all the skipping-over bits are for... |
| 666 | |
| 667 | We look for the first line starting with 'W', then expect ' |
| 668 | NUMBER\n' immediately after that, followed by NUMBER bytes |
| 669 | of plain blob content. |
| 670 | */ |
| 671 | int len; |
| 672 | char * it; |
| 673 | Blob numbuf; |
| 674 | blob_zero(&numbuf); |
| 675 | it = blob_buffer(&buf); |
| 676 | while(*it){ |
| 677 | if( *it != 'W' ){ |
| 678 | ++it; |
| 679 | while( *it ){ |
| 680 | if( *it == '\n') { ++it; break; } |
| 681 | ++it; |
| 682 | } |
| 683 | continue; |
| 684 | } |
| 685 | ++it; |
| 686 | while( (*it) && (*it != '\n') ){ |
| 687 | if( isspace(*it) ) { ++it; continue; } |
| 688 | blob_append(&numbuf,it,1); |
| 689 | ++it; |
| 690 | } |
| 691 | if( '\n' == *it ) ++it; |
| 692 | if( 0 == blob_size(&numbuf) ){ |
| 693 | fprintf(stderr, |
| 694 | "export error: didn't find \"W NUMBER\" line in input!\n"); |
| 695 | blob_zero(&buf); |
| 696 | blob_zero(&numbuf); |
| 697 | exit(1); |
| 698 | } |
| 699 | len = atoi(blob_buffer(&numbuf)); |
| 700 | //fprintf(stderr,"Writing %d (%s) bytes...\n",len,blob_buffer(&numbuf)); |
| 701 | blob_zero(&numbuf); |
| 702 | fwrite(it,sizeof(char),len,stdout); |
| 703 | blob_zero(&buf); |
| 704 | return; |
| 705 | } |
| 706 | } |
| 707 | blob_zero(&buf); |
| 708 | return; |
| 709 | }else |
| 710 | if( strncmp(g.argv[2],"import",n)==0 ){ |
| 711 | char *wname; |
| 712 | if( g.argc!=4 ){ |
| 713 | usage("import EntryName"); |
| 714 | } |
| 715 | wname = g.argv[3]; |
| 716 | fprintf(stderr,"import not yet implemented.\n"); |
| 717 | exit(1); |
| 718 | }else |
| 719 | if( strncmp(g.argv[2],"delete",n)==0 ){ |
| 720 | if( g.argc!=5 ){ |
| 721 | usage("delete WikiName"); |
| 722 | } |
| 723 | fprintf(stderr,"delete not yet implemented.\n"); |
| 724 | exit(1); |
| 725 | }else |
| 726 | if( strncmp(g.argv[2],"list",n)==0 ){ |
| 727 | Stmt q; |
| 728 | db_prepare(&q, |
| 729 | "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname GLOB 'wiki-*'" |
| 730 | " ORDER BY lower(tagname)" |
| 731 | ); |
| 732 | while( db_step(&q)==SQLITE_ROW ){ |
| 733 | const char *zName = db_column_text(&q, 0); |
| 734 | printf( "%s\n",zName); |
| 735 | } |
| 736 | db_finalize(&q); |
| 737 | }else |
| 738 | { |
| 739 | goto wiki_cmd_usage; |
| 740 | } |
| 741 | return; |
| 742 | |
| 743 | wiki_cmd_usage: |
| 744 | usage("delete|export|import|list [EntryName]"); |
| 745 | } |
| 746 | |
| 747 |