Fossil SCM
Merge the latest trunk changes into windows-i18n branch.
Commit
59ddd3c8ae134f41fd775c7ba7946452bffd2e65
Parent
503a0ef555dd376…
8 files changed
+22
-8
+22
-8
+63
-9
+63
-9
+7
-2
+7
-2
+2
-2
+2
-2
+22
-8
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -276,18 +276,32 @@ | ||
| 276 | 276 | @ reopened)</li> |
| 277 | 277 | @ </ol> |
| 278 | 278 | style_sidebox_end(); |
| 279 | 279 | |
| 280 | 280 | cnt = 0; |
| 281 | - db_prepare(&q, | |
| 282 | - "SELECT DISTINCT value FROM tagxref" | |
| 283 | - " WHERE tagid=%d AND value NOT NULL" | |
| 284 | - " AND rid IN leaf" | |
| 285 | - " AND %s %z" | |
| 286 | - " ORDER BY value /*sort*/", | |
| 287 | - TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") | |
| 288 | - ); | |
| 281 | + if( showClosed ){ | |
| 282 | + db_prepare(&q, | |
| 283 | + "SELECT value FROM tagxref" | |
| 284 | + " WHERE tagid=%d AND value NOT NULL " | |
| 285 | + "EXCEPT " | |
| 286 | + "SELECT value FROM tagxref" | |
| 287 | + " WHERE tagid=%d" | |
| 288 | + " AND rid IN leaf" | |
| 289 | + " AND NOT %z" | |
| 290 | + " ORDER BY value /*sort*/", | |
| 291 | + TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 292 | + ); | |
| 293 | + }else{ | |
| 294 | + db_prepare(&q, | |
| 295 | + "SELECT DISTINCT value FROM tagxref" | |
| 296 | + " WHERE tagid=%d AND value NOT NULL" | |
| 297 | + " AND rid IN leaf" | |
| 298 | + " AND NOT %z" | |
| 299 | + " ORDER BY value /*sort*/", | |
| 300 | + TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 301 | + ); | |
| 302 | + } | |
| 289 | 303 | while( db_step(&q)==SQLITE_ROW ){ |
| 290 | 304 | const char *zBr = db_column_text(&q, 0); |
| 291 | 305 | if( cnt==0 ){ |
| 292 | 306 | if( showClosed ){ |
| 293 | 307 | @ <h2>Closed Branches:</h2> |
| 294 | 308 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -276,18 +276,32 @@ | |
| 276 | @ reopened)</li> |
| 277 | @ </ol> |
| 278 | style_sidebox_end(); |
| 279 | |
| 280 | cnt = 0; |
| 281 | db_prepare(&q, |
| 282 | "SELECT DISTINCT value FROM tagxref" |
| 283 | " WHERE tagid=%d AND value NOT NULL" |
| 284 | " AND rid IN leaf" |
| 285 | " AND %s %z" |
| 286 | " ORDER BY value /*sort*/", |
| 287 | TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") |
| 288 | ); |
| 289 | while( db_step(&q)==SQLITE_ROW ){ |
| 290 | const char *zBr = db_column_text(&q, 0); |
| 291 | if( cnt==0 ){ |
| 292 | if( showClosed ){ |
| 293 | @ <h2>Closed Branches:</h2> |
| 294 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -276,18 +276,32 @@ | |
| 276 | @ reopened)</li> |
| 277 | @ </ol> |
| 278 | style_sidebox_end(); |
| 279 | |
| 280 | cnt = 0; |
| 281 | if( showClosed ){ |
| 282 | db_prepare(&q, |
| 283 | "SELECT value FROM tagxref" |
| 284 | " WHERE tagid=%d AND value NOT NULL " |
| 285 | "EXCEPT " |
| 286 | "SELECT value FROM tagxref" |
| 287 | " WHERE tagid=%d" |
| 288 | " AND rid IN leaf" |
| 289 | " AND NOT %z" |
| 290 | " ORDER BY value /*sort*/", |
| 291 | TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 292 | ); |
| 293 | }else{ |
| 294 | db_prepare(&q, |
| 295 | "SELECT DISTINCT value FROM tagxref" |
| 296 | " WHERE tagid=%d AND value NOT NULL" |
| 297 | " AND rid IN leaf" |
| 298 | " AND NOT %z" |
| 299 | " ORDER BY value /*sort*/", |
| 300 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 301 | ); |
| 302 | } |
| 303 | while( db_step(&q)==SQLITE_ROW ){ |
| 304 | const char *zBr = db_column_text(&q, 0); |
| 305 | if( cnt==0 ){ |
| 306 | if( showClosed ){ |
| 307 | @ <h2>Closed Branches:</h2> |
| 308 |
+22
-8
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -276,18 +276,32 @@ | ||
| 276 | 276 | @ reopened)</li> |
| 277 | 277 | @ </ol> |
| 278 | 278 | style_sidebox_end(); |
| 279 | 279 | |
| 280 | 280 | cnt = 0; |
| 281 | - db_prepare(&q, | |
| 282 | - "SELECT DISTINCT value FROM tagxref" | |
| 283 | - " WHERE tagid=%d AND value NOT NULL" | |
| 284 | - " AND rid IN leaf" | |
| 285 | - " AND %s %z" | |
| 286 | - " ORDER BY value /*sort*/", | |
| 287 | - TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") | |
| 288 | - ); | |
| 281 | + if( showClosed ){ | |
| 282 | + db_prepare(&q, | |
| 283 | + "SELECT value FROM tagxref" | |
| 284 | + " WHERE tagid=%d AND value NOT NULL " | |
| 285 | + "EXCEPT " | |
| 286 | + "SELECT value FROM tagxref" | |
| 287 | + " WHERE tagid=%d" | |
| 288 | + " AND rid IN leaf" | |
| 289 | + " AND NOT %z" | |
| 290 | + " ORDER BY value /*sort*/", | |
| 291 | + TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 292 | + ); | |
| 293 | + }else{ | |
| 294 | + db_prepare(&q, | |
| 295 | + "SELECT DISTINCT value FROM tagxref" | |
| 296 | + " WHERE tagid=%d AND value NOT NULL" | |
| 297 | + " AND rid IN leaf" | |
| 298 | + " AND NOT %z" | |
| 299 | + " ORDER BY value /*sort*/", | |
| 300 | + TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 301 | + ); | |
| 302 | + } | |
| 289 | 303 | while( db_step(&q)==SQLITE_ROW ){ |
| 290 | 304 | const char *zBr = db_column_text(&q, 0); |
| 291 | 305 | if( cnt==0 ){ |
| 292 | 306 | if( showClosed ){ |
| 293 | 307 | @ <h2>Closed Branches:</h2> |
| 294 | 308 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -276,18 +276,32 @@ | |
| 276 | @ reopened)</li> |
| 277 | @ </ol> |
| 278 | style_sidebox_end(); |
| 279 | |
| 280 | cnt = 0; |
| 281 | db_prepare(&q, |
| 282 | "SELECT DISTINCT value FROM tagxref" |
| 283 | " WHERE tagid=%d AND value NOT NULL" |
| 284 | " AND rid IN leaf" |
| 285 | " AND %s %z" |
| 286 | " ORDER BY value /*sort*/", |
| 287 | TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") |
| 288 | ); |
| 289 | while( db_step(&q)==SQLITE_ROW ){ |
| 290 | const char *zBr = db_column_text(&q, 0); |
| 291 | if( cnt==0 ){ |
| 292 | if( showClosed ){ |
| 293 | @ <h2>Closed Branches:</h2> |
| 294 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -276,18 +276,32 @@ | |
| 276 | @ reopened)</li> |
| 277 | @ </ol> |
| 278 | style_sidebox_end(); |
| 279 | |
| 280 | cnt = 0; |
| 281 | if( showClosed ){ |
| 282 | db_prepare(&q, |
| 283 | "SELECT value FROM tagxref" |
| 284 | " WHERE tagid=%d AND value NOT NULL " |
| 285 | "EXCEPT " |
| 286 | "SELECT value FROM tagxref" |
| 287 | " WHERE tagid=%d" |
| 288 | " AND rid IN leaf" |
| 289 | " AND NOT %z" |
| 290 | " ORDER BY value /*sort*/", |
| 291 | TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 292 | ); |
| 293 | }else{ |
| 294 | db_prepare(&q, |
| 295 | "SELECT DISTINCT value FROM tagxref" |
| 296 | " WHERE tagid=%d AND value NOT NULL" |
| 297 | " AND rid IN leaf" |
| 298 | " AND NOT %z" |
| 299 | " ORDER BY value /*sort*/", |
| 300 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 301 | ); |
| 302 | } |
| 303 | while( db_step(&q)==SQLITE_ROW ){ |
| 304 | const char *zBr = db_column_text(&q, 0); |
| 305 | if( cnt==0 ){ |
| 306 | if( showClosed ){ |
| 307 | @ <h2>Closed Branches:</h2> |
| 308 |
+63
-9
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -626,17 +626,21 @@ | ||
| 626 | 626 | ** of the following structure. |
| 627 | 627 | */ |
| 628 | 628 | typedef struct Annotator Annotator; |
| 629 | 629 | struct Annotator { |
| 630 | 630 | DContext c; /* The diff-engine context */ |
| 631 | - struct { /* Lines of the original files... */ | |
| 631 | + struct AnnLine { /* Lines of the original files... */ | |
| 632 | 632 | const char *z; /* The text of the line */ |
| 633 | - int n; /* Number of bytes (omitting trailing space and \n) */ | |
| 633 | + short int n; /* Number of bytes (omitting trailing space and \n) */ | |
| 634 | + short int iLevel; /* Level at which tag was set */ | |
| 634 | 635 | const char *zSrc; /* Tag showing origin of this line */ |
| 635 | 636 | } *aOrig; |
| 636 | 637 | int nOrig; /* Number of elements in aOrig[] */ |
| 637 | 638 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | + int iLevel; /* Current level */ | |
| 640 | + int nVers; /* Number of versions analyzed */ | |
| 641 | + char **azVers; /* Names of versions analyzed */ | |
| 638 | 642 | }; |
| 639 | 643 | |
| 640 | 644 | /* |
| 641 | 645 | ** Initialize the annotation process by specifying the file that is |
| 642 | 646 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | ||
| 668 | 672 | ** pParent. Memory to hold zPName is leaked. |
| 669 | 673 | */ |
| 670 | 674 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 671 | 675 | int i, j; |
| 672 | 676 | int lnTo; |
| 677 | + int iPrevLevel; | |
| 678 | + int iThisLevel; | |
| 673 | 679 | |
| 674 | 680 | /* Prepare the parent file to be diffed */ |
| 675 | 681 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 676 | 682 | &p->c.nFrom, 1); |
| 677 | 683 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | ||
| 683 | 689 | diff_all(&p->c); |
| 684 | 690 | |
| 685 | 691 | /* Where new lines are inserted on this difference, record the |
| 686 | 692 | ** zPName as the source of the new line. |
| 687 | 693 | */ |
| 694 | + iPrevLevel = p->iLevel; | |
| 695 | + p->iLevel++; | |
| 696 | + iThisLevel = p->iLevel; | |
| 688 | 697 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 689 | - for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ | |
| 690 | - p->aOrig[lnTo].zSrc = zPName; | |
| 698 | + struct AnnLine *x = &p->aOrig[lnTo]; | |
| 699 | + for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ | |
| 700 | + if( x->zSrc==0 || x->iLevel==iPrevLevel ){ | |
| 701 | + x->zSrc = zPName; | |
| 702 | + x->iLevel = iThisLevel; | |
| 703 | + } | |
| 691 | 704 | } |
| 692 | 705 | lnTo += p->c.aEdit[i+2]; |
| 693 | 706 | } |
| 694 | 707 | |
| 695 | 708 | /* Clear out the diff results */ |
| @@ -739,11 +752,17 @@ | ||
| 739 | 752 | /* |
| 740 | 753 | ** Compute a complete annotation on a file. The file is identified |
| 741 | 754 | ** by its filename number (filename.fnid) and the baseline in which |
| 742 | 755 | ** it was checked in (mlink.mid). |
| 743 | 756 | */ |
| 744 | -static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ | |
| 757 | +static void annotate_file( | |
| 758 | + Annotator *p, /* The annotator */ | |
| 759 | + int fnid, /* The name of the file to be annotated */ | |
| 760 | + int mid, /* The specific version of the file for this step */ | |
| 761 | + int webLabel, /* Use web-style annotations if true */ | |
| 762 | + int iLimit /* Limit the number of levels if greater than zero */ | |
| 763 | +){ | |
| 745 | 764 | Blob toAnnotate; /* Text of the final version of the file */ |
| 746 | 765 | Blob step; /* Text of previous revision */ |
| 747 | 766 | int rid; /* Artifact ID of the file being annotated */ |
| 748 | 767 | char *zLabel; /* Label to apply to a line */ |
| 749 | 768 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -766,12 +785,14 @@ | ||
| 766 | 785 | " FROM mlink, blob, event" |
| 767 | 786 | " WHERE mlink.fnid=%d" |
| 768 | 787 | " AND mlink.mid IN ok" |
| 769 | 788 | " AND blob.rid=mlink.mid" |
| 770 | 789 | " AND event.objid=mlink.mid" |
| 771 | - " ORDER BY event.mtime DESC", | |
| 772 | - fnid | |
| 790 | + " ORDER BY event.mtime DESC" | |
| 791 | + " LIMIT %d", | |
| 792 | + fnid, | |
| 793 | + iLimit>0 ? iLimit : 10000000 | |
| 773 | 794 | ); |
| 774 | 795 | while( db_step(&q)==SQLITE_ROW ){ |
| 775 | 796 | int pid = db_column_int(&q, 0); |
| 776 | 797 | const char *zUuid = db_column_text(&q, 1); |
| 777 | 798 | const char *zDate = db_column_text(&q, 2); |
| @@ -782,10 +803,13 @@ | ||
| 782 | 803 | g.zTop, zUuid, zUuid, zDate, zUser |
| 783 | 804 | ); |
| 784 | 805 | }else{ |
| 785 | 806 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 786 | 807 | } |
| 808 | + p->nVers++; | |
| 809 | + p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); | |
| 810 | + p->azVers[p->nVers-1] = zLabel; | |
| 787 | 811 | content_get(pid, &step); |
| 788 | 812 | annotation_step(p, &step, zLabel); |
| 789 | 813 | blob_reset(&step); |
| 790 | 814 | } |
| 791 | 815 | db_finalize(&q); |
| @@ -801,22 +825,35 @@ | ||
| 801 | 825 | */ |
| 802 | 826 | void annotation_page(void){ |
| 803 | 827 | int mid; |
| 804 | 828 | int fnid; |
| 805 | 829 | int i; |
| 830 | + int iLimit; | |
| 806 | 831 | Annotator ann; |
| 807 | 832 | |
| 808 | 833 | login_check_credentials(); |
| 809 | 834 | if( !g.okRead ){ login_needed(); return; } |
| 810 | 835 | mid = name_to_rid(PD("checkin","0")); |
| 811 | 836 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 812 | 837 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 838 | + iLimit = atoi(PD("limit","-1")); | |
| 813 | 839 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 814 | 840 | fossil_redirect_home(); |
| 815 | 841 | } |
| 816 | 842 | style_header("File Annotation"); |
| 817 | - annotate_file(&ann, fnid, mid, g.okHistory); | |
| 843 | + annotate_file(&ann, fnid, mid, g.okHistory, iLimit); | |
| 844 | + if( P("log") ){ | |
| 845 | + int i; | |
| 846 | + @ <h2>Versions analyzed:</h2> | |
| 847 | + @ <ol> | |
| 848 | + for(i=0; i<ann.nVers; i++){ | |
| 849 | + @ <li><tt>%s(ann.azVers[i])</tt></li> | |
| 850 | + } | |
| 851 | + @ </ol> | |
| 852 | + @ <hr> | |
| 853 | + @ <h2>Annotation:</h2> | |
| 854 | + } | |
| 818 | 855 | @ <pre> |
| 819 | 856 | for(i=0; i<ann.nOrig; i++){ |
| 820 | 857 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 821 | 858 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 822 | 859 | } |
| @@ -829,20 +866,31 @@ | ||
| 829 | 866 | ** |
| 830 | 867 | ** %fossil annotate FILENAME |
| 831 | 868 | ** |
| 832 | 869 | ** Output the text of a file with markings to show when each line of |
| 833 | 870 | ** the file was last modified. |
| 871 | +** | |
| 872 | +** Options: | |
| 873 | +** --limit N Only look backwards in time by N versions | |
| 874 | +** --log List all versions analyzed | |
| 834 | 875 | */ |
| 835 | 876 | void annotate_cmd(void){ |
| 836 | 877 | int fnid; /* Filename ID */ |
| 837 | 878 | int fid; /* File instance ID */ |
| 838 | 879 | int mid; /* Manifest where file was checked in */ |
| 839 | 880 | Blob treename; /* FILENAME translated to canonical form */ |
| 840 | 881 | char *zFilename; /* Cannonical filename */ |
| 841 | 882 | Annotator ann; /* The annotation of the file */ |
| 842 | 883 | int i; /* Loop counter */ |
| 884 | + const char *zLimit; /* The value to the --limit option */ | |
| 885 | + int iLimit; /* How far back in time to look */ | |
| 886 | + int showLog; /* True to show the log */ | |
| 843 | 887 | |
| 888 | + zLimit = find_option("limit",0,1); | |
| 889 | + if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; | |
| 890 | + iLimit = atoi(zLimit); | |
| 891 | + showLog = find_option("log",0,0)!=0; | |
| 844 | 892 | db_must_be_within_tree(); |
| 845 | 893 | if (g.argc<3) { |
| 846 | 894 | usage("FILENAME"); |
| 847 | 895 | } |
| 848 | 896 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -857,11 +905,17 @@ | ||
| 857 | 905 | } |
| 858 | 906 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 859 | 907 | if( mid==0 ){ |
| 860 | 908 | fossil_panic("unable to find manifest"); |
| 861 | 909 | } |
| 862 | - annotate_file(&ann, fnid, mid, 0); | |
| 910 | + annotate_file(&ann, fnid, mid, 0, iLimit); | |
| 911 | + if( showLog ){ | |
| 912 | + for(i=0; i<ann.nVers; i++){ | |
| 913 | + printf("version %3d: %s\n", i+1, ann.azVers[i]); | |
| 914 | + } | |
| 915 | + printf("---------------------------------------------------\n"); | |
| 916 | + } | |
| 863 | 917 | for(i=0; i<ann.nOrig; i++){ |
| 864 | 918 | fossil_print("%s: %.*s\n", |
| 865 | 919 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 866 | 920 | } |
| 867 | 921 | } |
| 868 | 922 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -626,17 +626,21 @@ | |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Annotator { |
| 630 | DContext c; /* The diff-engine context */ |
| 631 | struct { /* Lines of the original files... */ |
| 632 | const char *z; /* The text of the line */ |
| 633 | int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | const char *zSrc; /* Tag showing origin of this line */ |
| 635 | } *aOrig; |
| 636 | int nOrig; /* Number of elements in aOrig[] */ |
| 637 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 638 | }; |
| 639 | |
| 640 | /* |
| 641 | ** Initialize the annotation process by specifying the file that is |
| 642 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | |
| 668 | ** pParent. Memory to hold zPName is leaked. |
| 669 | */ |
| 670 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 671 | int i, j; |
| 672 | int lnTo; |
| 673 | |
| 674 | /* Prepare the parent file to be diffed */ |
| 675 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 676 | &p->c.nFrom, 1); |
| 677 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | |
| 683 | diff_all(&p->c); |
| 684 | |
| 685 | /* Where new lines are inserted on this difference, record the |
| 686 | ** zPName as the source of the new line. |
| 687 | */ |
| 688 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 689 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ |
| 690 | p->aOrig[lnTo].zSrc = zPName; |
| 691 | } |
| 692 | lnTo += p->c.aEdit[i+2]; |
| 693 | } |
| 694 | |
| 695 | /* Clear out the diff results */ |
| @@ -739,11 +752,17 @@ | |
| 739 | /* |
| 740 | ** Compute a complete annotation on a file. The file is identified |
| 741 | ** by its filename number (filename.fnid) and the baseline in which |
| 742 | ** it was checked in (mlink.mid). |
| 743 | */ |
| 744 | static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ |
| 745 | Blob toAnnotate; /* Text of the final version of the file */ |
| 746 | Blob step; /* Text of previous revision */ |
| 747 | int rid; /* Artifact ID of the file being annotated */ |
| 748 | char *zLabel; /* Label to apply to a line */ |
| 749 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -766,12 +785,14 @@ | |
| 766 | " FROM mlink, blob, event" |
| 767 | " WHERE mlink.fnid=%d" |
| 768 | " AND mlink.mid IN ok" |
| 769 | " AND blob.rid=mlink.mid" |
| 770 | " AND event.objid=mlink.mid" |
| 771 | " ORDER BY event.mtime DESC", |
| 772 | fnid |
| 773 | ); |
| 774 | while( db_step(&q)==SQLITE_ROW ){ |
| 775 | int pid = db_column_int(&q, 0); |
| 776 | const char *zUuid = db_column_text(&q, 1); |
| 777 | const char *zDate = db_column_text(&q, 2); |
| @@ -782,10 +803,13 @@ | |
| 782 | g.zTop, zUuid, zUuid, zDate, zUser |
| 783 | ); |
| 784 | }else{ |
| 785 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 786 | } |
| 787 | content_get(pid, &step); |
| 788 | annotation_step(p, &step, zLabel); |
| 789 | blob_reset(&step); |
| 790 | } |
| 791 | db_finalize(&q); |
| @@ -801,22 +825,35 @@ | |
| 801 | */ |
| 802 | void annotation_page(void){ |
| 803 | int mid; |
| 804 | int fnid; |
| 805 | int i; |
| 806 | Annotator ann; |
| 807 | |
| 808 | login_check_credentials(); |
| 809 | if( !g.okRead ){ login_needed(); return; } |
| 810 | mid = name_to_rid(PD("checkin","0")); |
| 811 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 812 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 813 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 814 | fossil_redirect_home(); |
| 815 | } |
| 816 | style_header("File Annotation"); |
| 817 | annotate_file(&ann, fnid, mid, g.okHistory); |
| 818 | @ <pre> |
| 819 | for(i=0; i<ann.nOrig; i++){ |
| 820 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 821 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 822 | } |
| @@ -829,20 +866,31 @@ | |
| 829 | ** |
| 830 | ** %fossil annotate FILENAME |
| 831 | ** |
| 832 | ** Output the text of a file with markings to show when each line of |
| 833 | ** the file was last modified. |
| 834 | */ |
| 835 | void annotate_cmd(void){ |
| 836 | int fnid; /* Filename ID */ |
| 837 | int fid; /* File instance ID */ |
| 838 | int mid; /* Manifest where file was checked in */ |
| 839 | Blob treename; /* FILENAME translated to canonical form */ |
| 840 | char *zFilename; /* Cannonical filename */ |
| 841 | Annotator ann; /* The annotation of the file */ |
| 842 | int i; /* Loop counter */ |
| 843 | |
| 844 | db_must_be_within_tree(); |
| 845 | if (g.argc<3) { |
| 846 | usage("FILENAME"); |
| 847 | } |
| 848 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -857,11 +905,17 @@ | |
| 857 | } |
| 858 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 859 | if( mid==0 ){ |
| 860 | fossil_panic("unable to find manifest"); |
| 861 | } |
| 862 | annotate_file(&ann, fnid, mid, 0); |
| 863 | for(i=0; i<ann.nOrig; i++){ |
| 864 | fossil_print("%s: %.*s\n", |
| 865 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 866 | } |
| 867 | } |
| 868 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -626,17 +626,21 @@ | |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Annotator { |
| 630 | DContext c; /* The diff-engine context */ |
| 631 | struct AnnLine { /* Lines of the original files... */ |
| 632 | const char *z; /* The text of the line */ |
| 633 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | short int iLevel; /* Level at which tag was set */ |
| 635 | const char *zSrc; /* Tag showing origin of this line */ |
| 636 | } *aOrig; |
| 637 | int nOrig; /* Number of elements in aOrig[] */ |
| 638 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | int iLevel; /* Current level */ |
| 640 | int nVers; /* Number of versions analyzed */ |
| 641 | char **azVers; /* Names of versions analyzed */ |
| 642 | }; |
| 643 | |
| 644 | /* |
| 645 | ** Initialize the annotation process by specifying the file that is |
| 646 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | |
| 672 | ** pParent. Memory to hold zPName is leaked. |
| 673 | */ |
| 674 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 675 | int i, j; |
| 676 | int lnTo; |
| 677 | int iPrevLevel; |
| 678 | int iThisLevel; |
| 679 | |
| 680 | /* Prepare the parent file to be diffed */ |
| 681 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 682 | &p->c.nFrom, 1); |
| 683 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | |
| 689 | diff_all(&p->c); |
| 690 | |
| 691 | /* Where new lines are inserted on this difference, record the |
| 692 | ** zPName as the source of the new line. |
| 693 | */ |
| 694 | iPrevLevel = p->iLevel; |
| 695 | p->iLevel++; |
| 696 | iThisLevel = p->iLevel; |
| 697 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 698 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 699 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 700 | if( x->zSrc==0 || x->iLevel==iPrevLevel ){ |
| 701 | x->zSrc = zPName; |
| 702 | x->iLevel = iThisLevel; |
| 703 | } |
| 704 | } |
| 705 | lnTo += p->c.aEdit[i+2]; |
| 706 | } |
| 707 | |
| 708 | /* Clear out the diff results */ |
| @@ -739,11 +752,17 @@ | |
| 752 | /* |
| 753 | ** Compute a complete annotation on a file. The file is identified |
| 754 | ** by its filename number (filename.fnid) and the baseline in which |
| 755 | ** it was checked in (mlink.mid). |
| 756 | */ |
| 757 | static void annotate_file( |
| 758 | Annotator *p, /* The annotator */ |
| 759 | int fnid, /* The name of the file to be annotated */ |
| 760 | int mid, /* The specific version of the file for this step */ |
| 761 | int webLabel, /* Use web-style annotations if true */ |
| 762 | int iLimit /* Limit the number of levels if greater than zero */ |
| 763 | ){ |
| 764 | Blob toAnnotate; /* Text of the final version of the file */ |
| 765 | Blob step; /* Text of previous revision */ |
| 766 | int rid; /* Artifact ID of the file being annotated */ |
| 767 | char *zLabel; /* Label to apply to a line */ |
| 768 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -766,12 +785,14 @@ | |
| 785 | " FROM mlink, blob, event" |
| 786 | " WHERE mlink.fnid=%d" |
| 787 | " AND mlink.mid IN ok" |
| 788 | " AND blob.rid=mlink.mid" |
| 789 | " AND event.objid=mlink.mid" |
| 790 | " ORDER BY event.mtime DESC" |
| 791 | " LIMIT %d", |
| 792 | fnid, |
| 793 | iLimit>0 ? iLimit : 10000000 |
| 794 | ); |
| 795 | while( db_step(&q)==SQLITE_ROW ){ |
| 796 | int pid = db_column_int(&q, 0); |
| 797 | const char *zUuid = db_column_text(&q, 1); |
| 798 | const char *zDate = db_column_text(&q, 2); |
| @@ -782,10 +803,13 @@ | |
| 803 | g.zTop, zUuid, zUuid, zDate, zUser |
| 804 | ); |
| 805 | }else{ |
| 806 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 807 | } |
| 808 | p->nVers++; |
| 809 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 810 | p->azVers[p->nVers-1] = zLabel; |
| 811 | content_get(pid, &step); |
| 812 | annotation_step(p, &step, zLabel); |
| 813 | blob_reset(&step); |
| 814 | } |
| 815 | db_finalize(&q); |
| @@ -801,22 +825,35 @@ | |
| 825 | */ |
| 826 | void annotation_page(void){ |
| 827 | int mid; |
| 828 | int fnid; |
| 829 | int i; |
| 830 | int iLimit; |
| 831 | Annotator ann; |
| 832 | |
| 833 | login_check_credentials(); |
| 834 | if( !g.okRead ){ login_needed(); return; } |
| 835 | mid = name_to_rid(PD("checkin","0")); |
| 836 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 837 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 838 | iLimit = atoi(PD("limit","-1")); |
| 839 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 840 | fossil_redirect_home(); |
| 841 | } |
| 842 | style_header("File Annotation"); |
| 843 | annotate_file(&ann, fnid, mid, g.okHistory, iLimit); |
| 844 | if( P("log") ){ |
| 845 | int i; |
| 846 | @ <h2>Versions analyzed:</h2> |
| 847 | @ <ol> |
| 848 | for(i=0; i<ann.nVers; i++){ |
| 849 | @ <li><tt>%s(ann.azVers[i])</tt></li> |
| 850 | } |
| 851 | @ </ol> |
| 852 | @ <hr> |
| 853 | @ <h2>Annotation:</h2> |
| 854 | } |
| 855 | @ <pre> |
| 856 | for(i=0; i<ann.nOrig; i++){ |
| 857 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 858 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 859 | } |
| @@ -829,20 +866,31 @@ | |
| 866 | ** |
| 867 | ** %fossil annotate FILENAME |
| 868 | ** |
| 869 | ** Output the text of a file with markings to show when each line of |
| 870 | ** the file was last modified. |
| 871 | ** |
| 872 | ** Options: |
| 873 | ** --limit N Only look backwards in time by N versions |
| 874 | ** --log List all versions analyzed |
| 875 | */ |
| 876 | void annotate_cmd(void){ |
| 877 | int fnid; /* Filename ID */ |
| 878 | int fid; /* File instance ID */ |
| 879 | int mid; /* Manifest where file was checked in */ |
| 880 | Blob treename; /* FILENAME translated to canonical form */ |
| 881 | char *zFilename; /* Cannonical filename */ |
| 882 | Annotator ann; /* The annotation of the file */ |
| 883 | int i; /* Loop counter */ |
| 884 | const char *zLimit; /* The value to the --limit option */ |
| 885 | int iLimit; /* How far back in time to look */ |
| 886 | int showLog; /* True to show the log */ |
| 887 | |
| 888 | zLimit = find_option("limit",0,1); |
| 889 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 890 | iLimit = atoi(zLimit); |
| 891 | showLog = find_option("log",0,0)!=0; |
| 892 | db_must_be_within_tree(); |
| 893 | if (g.argc<3) { |
| 894 | usage("FILENAME"); |
| 895 | } |
| 896 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -857,11 +905,17 @@ | |
| 905 | } |
| 906 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 907 | if( mid==0 ){ |
| 908 | fossil_panic("unable to find manifest"); |
| 909 | } |
| 910 | annotate_file(&ann, fnid, mid, 0, iLimit); |
| 911 | if( showLog ){ |
| 912 | for(i=0; i<ann.nVers; i++){ |
| 913 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 914 | } |
| 915 | printf("---------------------------------------------------\n"); |
| 916 | } |
| 917 | for(i=0; i<ann.nOrig; i++){ |
| 918 | fossil_print("%s: %.*s\n", |
| 919 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 920 | } |
| 921 | } |
| 922 |
+63
-9
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -626,17 +626,21 @@ | ||
| 626 | 626 | ** of the following structure. |
| 627 | 627 | */ |
| 628 | 628 | typedef struct Annotator Annotator; |
| 629 | 629 | struct Annotator { |
| 630 | 630 | DContext c; /* The diff-engine context */ |
| 631 | - struct { /* Lines of the original files... */ | |
| 631 | + struct AnnLine { /* Lines of the original files... */ | |
| 632 | 632 | const char *z; /* The text of the line */ |
| 633 | - int n; /* Number of bytes (omitting trailing space and \n) */ | |
| 633 | + short int n; /* Number of bytes (omitting trailing space and \n) */ | |
| 634 | + short int iLevel; /* Level at which tag was set */ | |
| 634 | 635 | const char *zSrc; /* Tag showing origin of this line */ |
| 635 | 636 | } *aOrig; |
| 636 | 637 | int nOrig; /* Number of elements in aOrig[] */ |
| 637 | 638 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | + int iLevel; /* Current level */ | |
| 640 | + int nVers; /* Number of versions analyzed */ | |
| 641 | + char **azVers; /* Names of versions analyzed */ | |
| 638 | 642 | }; |
| 639 | 643 | |
| 640 | 644 | /* |
| 641 | 645 | ** Initialize the annotation process by specifying the file that is |
| 642 | 646 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | ||
| 668 | 672 | ** pParent. Memory to hold zPName is leaked. |
| 669 | 673 | */ |
| 670 | 674 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 671 | 675 | int i, j; |
| 672 | 676 | int lnTo; |
| 677 | + int iPrevLevel; | |
| 678 | + int iThisLevel; | |
| 673 | 679 | |
| 674 | 680 | /* Prepare the parent file to be diffed */ |
| 675 | 681 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 676 | 682 | &p->c.nFrom, 1); |
| 677 | 683 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | ||
| 683 | 689 | diff_all(&p->c); |
| 684 | 690 | |
| 685 | 691 | /* Where new lines are inserted on this difference, record the |
| 686 | 692 | ** zPName as the source of the new line. |
| 687 | 693 | */ |
| 694 | + iPrevLevel = p->iLevel; | |
| 695 | + p->iLevel++; | |
| 696 | + iThisLevel = p->iLevel; | |
| 688 | 697 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 689 | - for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ | |
| 690 | - p->aOrig[lnTo].zSrc = zPName; | |
| 698 | + struct AnnLine *x = &p->aOrig[lnTo]; | |
| 699 | + for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ | |
| 700 | + if( x->zSrc==0 || x->iLevel==iPrevLevel ){ | |
| 701 | + x->zSrc = zPName; | |
| 702 | + x->iLevel = iThisLevel; | |
| 703 | + } | |
| 691 | 704 | } |
| 692 | 705 | lnTo += p->c.aEdit[i+2]; |
| 693 | 706 | } |
| 694 | 707 | |
| 695 | 708 | /* Clear out the diff results */ |
| @@ -739,11 +752,17 @@ | ||
| 739 | 752 | /* |
| 740 | 753 | ** Compute a complete annotation on a file. The file is identified |
| 741 | 754 | ** by its filename number (filename.fnid) and the baseline in which |
| 742 | 755 | ** it was checked in (mlink.mid). |
| 743 | 756 | */ |
| 744 | -static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ | |
| 757 | +static void annotate_file( | |
| 758 | + Annotator *p, /* The annotator */ | |
| 759 | + int fnid, /* The name of the file to be annotated */ | |
| 760 | + int mid, /* The specific version of the file for this step */ | |
| 761 | + int webLabel, /* Use web-style annotations if true */ | |
| 762 | + int iLimit /* Limit the number of levels if greater than zero */ | |
| 763 | +){ | |
| 745 | 764 | Blob toAnnotate; /* Text of the final version of the file */ |
| 746 | 765 | Blob step; /* Text of previous revision */ |
| 747 | 766 | int rid; /* Artifact ID of the file being annotated */ |
| 748 | 767 | char *zLabel; /* Label to apply to a line */ |
| 749 | 768 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -766,12 +785,14 @@ | ||
| 766 | 785 | " FROM mlink, blob, event" |
| 767 | 786 | " WHERE mlink.fnid=%d" |
| 768 | 787 | " AND mlink.mid IN ok" |
| 769 | 788 | " AND blob.rid=mlink.mid" |
| 770 | 789 | " AND event.objid=mlink.mid" |
| 771 | - " ORDER BY event.mtime DESC", | |
| 772 | - fnid | |
| 790 | + " ORDER BY event.mtime DESC" | |
| 791 | + " LIMIT %d", | |
| 792 | + fnid, | |
| 793 | + iLimit>0 ? iLimit : 10000000 | |
| 773 | 794 | ); |
| 774 | 795 | while( db_step(&q)==SQLITE_ROW ){ |
| 775 | 796 | int pid = db_column_int(&q, 0); |
| 776 | 797 | const char *zUuid = db_column_text(&q, 1); |
| 777 | 798 | const char *zDate = db_column_text(&q, 2); |
| @@ -782,10 +803,13 @@ | ||
| 782 | 803 | g.zTop, zUuid, zUuid, zDate, zUser |
| 783 | 804 | ); |
| 784 | 805 | }else{ |
| 785 | 806 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 786 | 807 | } |
| 808 | + p->nVers++; | |
| 809 | + p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); | |
| 810 | + p->azVers[p->nVers-1] = zLabel; | |
| 787 | 811 | content_get(pid, &step); |
| 788 | 812 | annotation_step(p, &step, zLabel); |
| 789 | 813 | blob_reset(&step); |
| 790 | 814 | } |
| 791 | 815 | db_finalize(&q); |
| @@ -801,22 +825,35 @@ | ||
| 801 | 825 | */ |
| 802 | 826 | void annotation_page(void){ |
| 803 | 827 | int mid; |
| 804 | 828 | int fnid; |
| 805 | 829 | int i; |
| 830 | + int iLimit; | |
| 806 | 831 | Annotator ann; |
| 807 | 832 | |
| 808 | 833 | login_check_credentials(); |
| 809 | 834 | if( !g.okRead ){ login_needed(); return; } |
| 810 | 835 | mid = name_to_rid(PD("checkin","0")); |
| 811 | 836 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 812 | 837 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 838 | + iLimit = atoi(PD("limit","-1")); | |
| 813 | 839 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 814 | 840 | fossil_redirect_home(); |
| 815 | 841 | } |
| 816 | 842 | style_header("File Annotation"); |
| 817 | - annotate_file(&ann, fnid, mid, g.okHistory); | |
| 843 | + annotate_file(&ann, fnid, mid, g.okHistory, iLimit); | |
| 844 | + if( P("log") ){ | |
| 845 | + int i; | |
| 846 | + @ <h2>Versions analyzed:</h2> | |
| 847 | + @ <ol> | |
| 848 | + for(i=0; i<ann.nVers; i++){ | |
| 849 | + @ <li><tt>%s(ann.azVers[i])</tt></li> | |
| 850 | + } | |
| 851 | + @ </ol> | |
| 852 | + @ <hr> | |
| 853 | + @ <h2>Annotation:</h2> | |
| 854 | + } | |
| 818 | 855 | @ <pre> |
| 819 | 856 | for(i=0; i<ann.nOrig; i++){ |
| 820 | 857 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 821 | 858 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 822 | 859 | } |
| @@ -829,20 +866,31 @@ | ||
| 829 | 866 | ** |
| 830 | 867 | ** %fossil annotate FILENAME |
| 831 | 868 | ** |
| 832 | 869 | ** Output the text of a file with markings to show when each line of |
| 833 | 870 | ** the file was last modified. |
| 871 | +** | |
| 872 | +** Options: | |
| 873 | +** --limit N Only look backwards in time by N versions | |
| 874 | +** --log List all versions analyzed | |
| 834 | 875 | */ |
| 835 | 876 | void annotate_cmd(void){ |
| 836 | 877 | int fnid; /* Filename ID */ |
| 837 | 878 | int fid; /* File instance ID */ |
| 838 | 879 | int mid; /* Manifest where file was checked in */ |
| 839 | 880 | Blob treename; /* FILENAME translated to canonical form */ |
| 840 | 881 | char *zFilename; /* Cannonical filename */ |
| 841 | 882 | Annotator ann; /* The annotation of the file */ |
| 842 | 883 | int i; /* Loop counter */ |
| 884 | + const char *zLimit; /* The value to the --limit option */ | |
| 885 | + int iLimit; /* How far back in time to look */ | |
| 886 | + int showLog; /* True to show the log */ | |
| 843 | 887 | |
| 888 | + zLimit = find_option("limit",0,1); | |
| 889 | + if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; | |
| 890 | + iLimit = atoi(zLimit); | |
| 891 | + showLog = find_option("log",0,0)!=0; | |
| 844 | 892 | db_must_be_within_tree(); |
| 845 | 893 | if (g.argc<3) { |
| 846 | 894 | usage("FILENAME"); |
| 847 | 895 | } |
| 848 | 896 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -857,11 +905,17 @@ | ||
| 857 | 905 | } |
| 858 | 906 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 859 | 907 | if( mid==0 ){ |
| 860 | 908 | fossil_panic("unable to find manifest"); |
| 861 | 909 | } |
| 862 | - annotate_file(&ann, fnid, mid, 0); | |
| 910 | + annotate_file(&ann, fnid, mid, 0, iLimit); | |
| 911 | + if( showLog ){ | |
| 912 | + for(i=0; i<ann.nVers; i++){ | |
| 913 | + printf("version %3d: %s\n", i+1, ann.azVers[i]); | |
| 914 | + } | |
| 915 | + printf("---------------------------------------------------\n"); | |
| 916 | + } | |
| 863 | 917 | for(i=0; i<ann.nOrig; i++){ |
| 864 | 918 | fossil_print("%s: %.*s\n", |
| 865 | 919 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 866 | 920 | } |
| 867 | 921 | } |
| 868 | 922 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -626,17 +626,21 @@ | |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Annotator { |
| 630 | DContext c; /* The diff-engine context */ |
| 631 | struct { /* Lines of the original files... */ |
| 632 | const char *z; /* The text of the line */ |
| 633 | int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | const char *zSrc; /* Tag showing origin of this line */ |
| 635 | } *aOrig; |
| 636 | int nOrig; /* Number of elements in aOrig[] */ |
| 637 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 638 | }; |
| 639 | |
| 640 | /* |
| 641 | ** Initialize the annotation process by specifying the file that is |
| 642 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | |
| 668 | ** pParent. Memory to hold zPName is leaked. |
| 669 | */ |
| 670 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 671 | int i, j; |
| 672 | int lnTo; |
| 673 | |
| 674 | /* Prepare the parent file to be diffed */ |
| 675 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 676 | &p->c.nFrom, 1); |
| 677 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | |
| 683 | diff_all(&p->c); |
| 684 | |
| 685 | /* Where new lines are inserted on this difference, record the |
| 686 | ** zPName as the source of the new line. |
| 687 | */ |
| 688 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 689 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ |
| 690 | p->aOrig[lnTo].zSrc = zPName; |
| 691 | } |
| 692 | lnTo += p->c.aEdit[i+2]; |
| 693 | } |
| 694 | |
| 695 | /* Clear out the diff results */ |
| @@ -739,11 +752,17 @@ | |
| 739 | /* |
| 740 | ** Compute a complete annotation on a file. The file is identified |
| 741 | ** by its filename number (filename.fnid) and the baseline in which |
| 742 | ** it was checked in (mlink.mid). |
| 743 | */ |
| 744 | static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ |
| 745 | Blob toAnnotate; /* Text of the final version of the file */ |
| 746 | Blob step; /* Text of previous revision */ |
| 747 | int rid; /* Artifact ID of the file being annotated */ |
| 748 | char *zLabel; /* Label to apply to a line */ |
| 749 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -766,12 +785,14 @@ | |
| 766 | " FROM mlink, blob, event" |
| 767 | " WHERE mlink.fnid=%d" |
| 768 | " AND mlink.mid IN ok" |
| 769 | " AND blob.rid=mlink.mid" |
| 770 | " AND event.objid=mlink.mid" |
| 771 | " ORDER BY event.mtime DESC", |
| 772 | fnid |
| 773 | ); |
| 774 | while( db_step(&q)==SQLITE_ROW ){ |
| 775 | int pid = db_column_int(&q, 0); |
| 776 | const char *zUuid = db_column_text(&q, 1); |
| 777 | const char *zDate = db_column_text(&q, 2); |
| @@ -782,10 +803,13 @@ | |
| 782 | g.zTop, zUuid, zUuid, zDate, zUser |
| 783 | ); |
| 784 | }else{ |
| 785 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 786 | } |
| 787 | content_get(pid, &step); |
| 788 | annotation_step(p, &step, zLabel); |
| 789 | blob_reset(&step); |
| 790 | } |
| 791 | db_finalize(&q); |
| @@ -801,22 +825,35 @@ | |
| 801 | */ |
| 802 | void annotation_page(void){ |
| 803 | int mid; |
| 804 | int fnid; |
| 805 | int i; |
| 806 | Annotator ann; |
| 807 | |
| 808 | login_check_credentials(); |
| 809 | if( !g.okRead ){ login_needed(); return; } |
| 810 | mid = name_to_rid(PD("checkin","0")); |
| 811 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 812 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 813 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 814 | fossil_redirect_home(); |
| 815 | } |
| 816 | style_header("File Annotation"); |
| 817 | annotate_file(&ann, fnid, mid, g.okHistory); |
| 818 | @ <pre> |
| 819 | for(i=0; i<ann.nOrig; i++){ |
| 820 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 821 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 822 | } |
| @@ -829,20 +866,31 @@ | |
| 829 | ** |
| 830 | ** %fossil annotate FILENAME |
| 831 | ** |
| 832 | ** Output the text of a file with markings to show when each line of |
| 833 | ** the file was last modified. |
| 834 | */ |
| 835 | void annotate_cmd(void){ |
| 836 | int fnid; /* Filename ID */ |
| 837 | int fid; /* File instance ID */ |
| 838 | int mid; /* Manifest where file was checked in */ |
| 839 | Blob treename; /* FILENAME translated to canonical form */ |
| 840 | char *zFilename; /* Cannonical filename */ |
| 841 | Annotator ann; /* The annotation of the file */ |
| 842 | int i; /* Loop counter */ |
| 843 | |
| 844 | db_must_be_within_tree(); |
| 845 | if (g.argc<3) { |
| 846 | usage("FILENAME"); |
| 847 | } |
| 848 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -857,11 +905,17 @@ | |
| 857 | } |
| 858 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 859 | if( mid==0 ){ |
| 860 | fossil_panic("unable to find manifest"); |
| 861 | } |
| 862 | annotate_file(&ann, fnid, mid, 0); |
| 863 | for(i=0; i<ann.nOrig; i++){ |
| 864 | fossil_print("%s: %.*s\n", |
| 865 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 866 | } |
| 867 | } |
| 868 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -626,17 +626,21 @@ | |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Annotator { |
| 630 | DContext c; /* The diff-engine context */ |
| 631 | struct AnnLine { /* Lines of the original files... */ |
| 632 | const char *z; /* The text of the line */ |
| 633 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | short int iLevel; /* Level at which tag was set */ |
| 635 | const char *zSrc; /* Tag showing origin of this line */ |
| 636 | } *aOrig; |
| 637 | int nOrig; /* Number of elements in aOrig[] */ |
| 638 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | int iLevel; /* Current level */ |
| 640 | int nVers; /* Number of versions analyzed */ |
| 641 | char **azVers; /* Names of versions analyzed */ |
| 642 | }; |
| 643 | |
| 644 | /* |
| 645 | ** Initialize the annotation process by specifying the file that is |
| 646 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | |
| 672 | ** pParent. Memory to hold zPName is leaked. |
| 673 | */ |
| 674 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 675 | int i, j; |
| 676 | int lnTo; |
| 677 | int iPrevLevel; |
| 678 | int iThisLevel; |
| 679 | |
| 680 | /* Prepare the parent file to be diffed */ |
| 681 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 682 | &p->c.nFrom, 1); |
| 683 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | |
| 689 | diff_all(&p->c); |
| 690 | |
| 691 | /* Where new lines are inserted on this difference, record the |
| 692 | ** zPName as the source of the new line. |
| 693 | */ |
| 694 | iPrevLevel = p->iLevel; |
| 695 | p->iLevel++; |
| 696 | iThisLevel = p->iLevel; |
| 697 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 698 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 699 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 700 | if( x->zSrc==0 || x->iLevel==iPrevLevel ){ |
| 701 | x->zSrc = zPName; |
| 702 | x->iLevel = iThisLevel; |
| 703 | } |
| 704 | } |
| 705 | lnTo += p->c.aEdit[i+2]; |
| 706 | } |
| 707 | |
| 708 | /* Clear out the diff results */ |
| @@ -739,11 +752,17 @@ | |
| 752 | /* |
| 753 | ** Compute a complete annotation on a file. The file is identified |
| 754 | ** by its filename number (filename.fnid) and the baseline in which |
| 755 | ** it was checked in (mlink.mid). |
| 756 | */ |
| 757 | static void annotate_file( |
| 758 | Annotator *p, /* The annotator */ |
| 759 | int fnid, /* The name of the file to be annotated */ |
| 760 | int mid, /* The specific version of the file for this step */ |
| 761 | int webLabel, /* Use web-style annotations if true */ |
| 762 | int iLimit /* Limit the number of levels if greater than zero */ |
| 763 | ){ |
| 764 | Blob toAnnotate; /* Text of the final version of the file */ |
| 765 | Blob step; /* Text of previous revision */ |
| 766 | int rid; /* Artifact ID of the file being annotated */ |
| 767 | char *zLabel; /* Label to apply to a line */ |
| 768 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -766,12 +785,14 @@ | |
| 785 | " FROM mlink, blob, event" |
| 786 | " WHERE mlink.fnid=%d" |
| 787 | " AND mlink.mid IN ok" |
| 788 | " AND blob.rid=mlink.mid" |
| 789 | " AND event.objid=mlink.mid" |
| 790 | " ORDER BY event.mtime DESC" |
| 791 | " LIMIT %d", |
| 792 | fnid, |
| 793 | iLimit>0 ? iLimit : 10000000 |
| 794 | ); |
| 795 | while( db_step(&q)==SQLITE_ROW ){ |
| 796 | int pid = db_column_int(&q, 0); |
| 797 | const char *zUuid = db_column_text(&q, 1); |
| 798 | const char *zDate = db_column_text(&q, 2); |
| @@ -782,10 +803,13 @@ | |
| 803 | g.zTop, zUuid, zUuid, zDate, zUser |
| 804 | ); |
| 805 | }else{ |
| 806 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 807 | } |
| 808 | p->nVers++; |
| 809 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 810 | p->azVers[p->nVers-1] = zLabel; |
| 811 | content_get(pid, &step); |
| 812 | annotation_step(p, &step, zLabel); |
| 813 | blob_reset(&step); |
| 814 | } |
| 815 | db_finalize(&q); |
| @@ -801,22 +825,35 @@ | |
| 825 | */ |
| 826 | void annotation_page(void){ |
| 827 | int mid; |
| 828 | int fnid; |
| 829 | int i; |
| 830 | int iLimit; |
| 831 | Annotator ann; |
| 832 | |
| 833 | login_check_credentials(); |
| 834 | if( !g.okRead ){ login_needed(); return; } |
| 835 | mid = name_to_rid(PD("checkin","0")); |
| 836 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 837 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 838 | iLimit = atoi(PD("limit","-1")); |
| 839 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 840 | fossil_redirect_home(); |
| 841 | } |
| 842 | style_header("File Annotation"); |
| 843 | annotate_file(&ann, fnid, mid, g.okHistory, iLimit); |
| 844 | if( P("log") ){ |
| 845 | int i; |
| 846 | @ <h2>Versions analyzed:</h2> |
| 847 | @ <ol> |
| 848 | for(i=0; i<ann.nVers; i++){ |
| 849 | @ <li><tt>%s(ann.azVers[i])</tt></li> |
| 850 | } |
| 851 | @ </ol> |
| 852 | @ <hr> |
| 853 | @ <h2>Annotation:</h2> |
| 854 | } |
| 855 | @ <pre> |
| 856 | for(i=0; i<ann.nOrig; i++){ |
| 857 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 858 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 859 | } |
| @@ -829,20 +866,31 @@ | |
| 866 | ** |
| 867 | ** %fossil annotate FILENAME |
| 868 | ** |
| 869 | ** Output the text of a file with markings to show when each line of |
| 870 | ** the file was last modified. |
| 871 | ** |
| 872 | ** Options: |
| 873 | ** --limit N Only look backwards in time by N versions |
| 874 | ** --log List all versions analyzed |
| 875 | */ |
| 876 | void annotate_cmd(void){ |
| 877 | int fnid; /* Filename ID */ |
| 878 | int fid; /* File instance ID */ |
| 879 | int mid; /* Manifest where file was checked in */ |
| 880 | Blob treename; /* FILENAME translated to canonical form */ |
| 881 | char *zFilename; /* Cannonical filename */ |
| 882 | Annotator ann; /* The annotation of the file */ |
| 883 | int i; /* Loop counter */ |
| 884 | const char *zLimit; /* The value to the --limit option */ |
| 885 | int iLimit; /* How far back in time to look */ |
| 886 | int showLog; /* True to show the log */ |
| 887 | |
| 888 | zLimit = find_option("limit",0,1); |
| 889 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 890 | iLimit = atoi(zLimit); |
| 891 | showLog = find_option("log",0,0)!=0; |
| 892 | db_must_be_within_tree(); |
| 893 | if (g.argc<3) { |
| 894 | usage("FILENAME"); |
| 895 | } |
| 896 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -857,11 +905,17 @@ | |
| 905 | } |
| 906 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 907 | if( mid==0 ){ |
| 908 | fossil_panic("unable to find manifest"); |
| 909 | } |
| 910 | annotate_file(&ann, fnid, mid, 0, iLimit); |
| 911 | if( showLog ){ |
| 912 | for(i=0; i<ann.nVers; i++){ |
| 913 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 914 | } |
| 915 | printf("---------------------------------------------------\n"); |
| 916 | } |
| 917 | for(i=0; i<ann.nOrig; i++){ |
| 918 | fossil_print("%s: %.*s\n", |
| 919 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 920 | } |
| 921 | } |
| 922 |
+7
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -949,16 +949,20 @@ | ||
| 949 | 949 | */ |
| 950 | 950 | void diff_page(void){ |
| 951 | 951 | int v1, v2; |
| 952 | 952 | int isPatch; |
| 953 | 953 | Blob c1, c2, diff, *pOut; |
| 954 | + char *zV1; | |
| 955 | + char *zV2; | |
| 954 | 956 | |
| 955 | 957 | login_check_credentials(); |
| 956 | 958 | if( !g.okRead ){ login_needed(); return; } |
| 957 | 959 | v1 = name_to_rid_www("v1"); |
| 958 | 960 | v2 = name_to_rid_www("v2"); |
| 959 | 961 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 962 | + zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); | |
| 963 | + zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); | |
| 960 | 964 | isPatch = P("patch")!=0; |
| 961 | 965 | if( isPatch ){ |
| 962 | 966 | pOut = cgi_output_blob(); |
| 963 | 967 | cgi_set_content_type("text/plain"); |
| 964 | 968 | }else{ |
| @@ -972,15 +976,16 @@ | ||
| 972 | 976 | blob_reset(&c2); |
| 973 | 977 | if( !isPatch ){ |
| 974 | 978 | style_header("Diff"); |
| 975 | 979 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 976 | 980 | g.zTop, P("v1"), P("v2")); |
| 977 | - @ <h2>Differences From:</h2> | |
| 981 | + @ <h2>Differences From | |
| 982 | + @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> | |
| 978 | 983 | @ <blockquote><p> |
| 979 | 984 | object_description(v1, 1, 0); |
| 980 | 985 | @ </p></blockquote> |
| 981 | - @ <h2>To:</h2> | |
| 986 | + @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> | |
| 982 | 987 | @ <blockquote><p> |
| 983 | 988 | object_description(v2, 1, 0); |
| 984 | 989 | @ </p></blockquote> |
| 985 | 990 | @ <hr /> |
| 986 | 991 | @ <blockquote><pre> |
| 987 | 992 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -949,16 +949,20 @@ | |
| 949 | */ |
| 950 | void diff_page(void){ |
| 951 | int v1, v2; |
| 952 | int isPatch; |
| 953 | Blob c1, c2, diff, *pOut; |
| 954 | |
| 955 | login_check_credentials(); |
| 956 | if( !g.okRead ){ login_needed(); return; } |
| 957 | v1 = name_to_rid_www("v1"); |
| 958 | v2 = name_to_rid_www("v2"); |
| 959 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 960 | isPatch = P("patch")!=0; |
| 961 | if( isPatch ){ |
| 962 | pOut = cgi_output_blob(); |
| 963 | cgi_set_content_type("text/plain"); |
| 964 | }else{ |
| @@ -972,15 +976,16 @@ | |
| 972 | blob_reset(&c2); |
| 973 | if( !isPatch ){ |
| 974 | style_header("Diff"); |
| 975 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 976 | g.zTop, P("v1"), P("v2")); |
| 977 | @ <h2>Differences From:</h2> |
| 978 | @ <blockquote><p> |
| 979 | object_description(v1, 1, 0); |
| 980 | @ </p></blockquote> |
| 981 | @ <h2>To:</h2> |
| 982 | @ <blockquote><p> |
| 983 | object_description(v2, 1, 0); |
| 984 | @ </p></blockquote> |
| 985 | @ <hr /> |
| 986 | @ <blockquote><pre> |
| 987 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -949,16 +949,20 @@ | |
| 949 | */ |
| 950 | void diff_page(void){ |
| 951 | int v1, v2; |
| 952 | int isPatch; |
| 953 | Blob c1, c2, diff, *pOut; |
| 954 | char *zV1; |
| 955 | char *zV2; |
| 956 | |
| 957 | login_check_credentials(); |
| 958 | if( !g.okRead ){ login_needed(); return; } |
| 959 | v1 = name_to_rid_www("v1"); |
| 960 | v2 = name_to_rid_www("v2"); |
| 961 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 962 | zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); |
| 963 | zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); |
| 964 | isPatch = P("patch")!=0; |
| 965 | if( isPatch ){ |
| 966 | pOut = cgi_output_blob(); |
| 967 | cgi_set_content_type("text/plain"); |
| 968 | }else{ |
| @@ -972,15 +976,16 @@ | |
| 976 | blob_reset(&c2); |
| 977 | if( !isPatch ){ |
| 978 | style_header("Diff"); |
| 979 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 980 | g.zTop, P("v1"), P("v2")); |
| 981 | @ <h2>Differences From |
| 982 | @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> |
| 983 | @ <blockquote><p> |
| 984 | object_description(v1, 1, 0); |
| 985 | @ </p></blockquote> |
| 986 | @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> |
| 987 | @ <blockquote><p> |
| 988 | object_description(v2, 1, 0); |
| 989 | @ </p></blockquote> |
| 990 | @ <hr /> |
| 991 | @ <blockquote><pre> |
| 992 |
+7
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -949,16 +949,20 @@ | ||
| 949 | 949 | */ |
| 950 | 950 | void diff_page(void){ |
| 951 | 951 | int v1, v2; |
| 952 | 952 | int isPatch; |
| 953 | 953 | Blob c1, c2, diff, *pOut; |
| 954 | + char *zV1; | |
| 955 | + char *zV2; | |
| 954 | 956 | |
| 955 | 957 | login_check_credentials(); |
| 956 | 958 | if( !g.okRead ){ login_needed(); return; } |
| 957 | 959 | v1 = name_to_rid_www("v1"); |
| 958 | 960 | v2 = name_to_rid_www("v2"); |
| 959 | 961 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 962 | + zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); | |
| 963 | + zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); | |
| 960 | 964 | isPatch = P("patch")!=0; |
| 961 | 965 | if( isPatch ){ |
| 962 | 966 | pOut = cgi_output_blob(); |
| 963 | 967 | cgi_set_content_type("text/plain"); |
| 964 | 968 | }else{ |
| @@ -972,15 +976,16 @@ | ||
| 972 | 976 | blob_reset(&c2); |
| 973 | 977 | if( !isPatch ){ |
| 974 | 978 | style_header("Diff"); |
| 975 | 979 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 976 | 980 | g.zTop, P("v1"), P("v2")); |
| 977 | - @ <h2>Differences From:</h2> | |
| 981 | + @ <h2>Differences From | |
| 982 | + @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> | |
| 978 | 983 | @ <blockquote><p> |
| 979 | 984 | object_description(v1, 1, 0); |
| 980 | 985 | @ </p></blockquote> |
| 981 | - @ <h2>To:</h2> | |
| 986 | + @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> | |
| 982 | 987 | @ <blockquote><p> |
| 983 | 988 | object_description(v2, 1, 0); |
| 984 | 989 | @ </p></blockquote> |
| 985 | 990 | @ <hr /> |
| 986 | 991 | @ <blockquote><pre> |
| 987 | 992 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -949,16 +949,20 @@ | |
| 949 | */ |
| 950 | void diff_page(void){ |
| 951 | int v1, v2; |
| 952 | int isPatch; |
| 953 | Blob c1, c2, diff, *pOut; |
| 954 | |
| 955 | login_check_credentials(); |
| 956 | if( !g.okRead ){ login_needed(); return; } |
| 957 | v1 = name_to_rid_www("v1"); |
| 958 | v2 = name_to_rid_www("v2"); |
| 959 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 960 | isPatch = P("patch")!=0; |
| 961 | if( isPatch ){ |
| 962 | pOut = cgi_output_blob(); |
| 963 | cgi_set_content_type("text/plain"); |
| 964 | }else{ |
| @@ -972,15 +976,16 @@ | |
| 972 | blob_reset(&c2); |
| 973 | if( !isPatch ){ |
| 974 | style_header("Diff"); |
| 975 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 976 | g.zTop, P("v1"), P("v2")); |
| 977 | @ <h2>Differences From:</h2> |
| 978 | @ <blockquote><p> |
| 979 | object_description(v1, 1, 0); |
| 980 | @ </p></blockquote> |
| 981 | @ <h2>To:</h2> |
| 982 | @ <blockquote><p> |
| 983 | object_description(v2, 1, 0); |
| 984 | @ </p></blockquote> |
| 985 | @ <hr /> |
| 986 | @ <blockquote><pre> |
| 987 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -949,16 +949,20 @@ | |
| 949 | */ |
| 950 | void diff_page(void){ |
| 951 | int v1, v2; |
| 952 | int isPatch; |
| 953 | Blob c1, c2, diff, *pOut; |
| 954 | char *zV1; |
| 955 | char *zV2; |
| 956 | |
| 957 | login_check_credentials(); |
| 958 | if( !g.okRead ){ login_needed(); return; } |
| 959 | v1 = name_to_rid_www("v1"); |
| 960 | v2 = name_to_rid_www("v2"); |
| 961 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 962 | zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); |
| 963 | zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); |
| 964 | isPatch = P("patch")!=0; |
| 965 | if( isPatch ){ |
| 966 | pOut = cgi_output_blob(); |
| 967 | cgi_set_content_type("text/plain"); |
| 968 | }else{ |
| @@ -972,15 +976,16 @@ | |
| 976 | blob_reset(&c2); |
| 977 | if( !isPatch ){ |
| 978 | style_header("Diff"); |
| 979 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 980 | g.zTop, P("v1"), P("v2")); |
| 981 | @ <h2>Differences From |
| 982 | @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> |
| 983 | @ <blockquote><p> |
| 984 | object_description(v1, 1, 0); |
| 985 | @ </p></blockquote> |
| 986 | @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> |
| 987 | @ <blockquote><p> |
| 988 | object_description(v2, 1, 0); |
| 989 | @ </p></blockquote> |
| 990 | @ <hr /> |
| 991 | @ <blockquote><pre> |
| 992 |
+2
-2
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -301,15 +301,15 @@ | ||
| 301 | 301 | */ |
| 302 | 302 | int vfile_top_of_checkout(const char *zPath){ |
| 303 | 303 | char *zFile; |
| 304 | 304 | int fileFound = 0; |
| 305 | 305 | |
| 306 | - zFile = mprintf("%s/_FOSSIL_"); | |
| 306 | + zFile = mprintf("%s/_FOSSIL_", zPath); | |
| 307 | 307 | fileFound = file_size(zFile)>=1024; |
| 308 | 308 | fossil_free(zFile); |
| 309 | 309 | if( !fileFound ){ |
| 310 | - zFile = mprintf("%s/.fos"); | |
| 310 | + zFile = mprintf("%s/.fos", zPath); | |
| 311 | 311 | fileFound = file_size(zFile)>=1024; |
| 312 | 312 | fossil_free(zFile); |
| 313 | 313 | } |
| 314 | 314 | return fileFound; |
| 315 | 315 | } |
| 316 | 316 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -301,15 +301,15 @@ | |
| 301 | */ |
| 302 | int vfile_top_of_checkout(const char *zPath){ |
| 303 | char *zFile; |
| 304 | int fileFound = 0; |
| 305 | |
| 306 | zFile = mprintf("%s/_FOSSIL_"); |
| 307 | fileFound = file_size(zFile)>=1024; |
| 308 | fossil_free(zFile); |
| 309 | if( !fileFound ){ |
| 310 | zFile = mprintf("%s/.fos"); |
| 311 | fileFound = file_size(zFile)>=1024; |
| 312 | fossil_free(zFile); |
| 313 | } |
| 314 | return fileFound; |
| 315 | } |
| 316 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -301,15 +301,15 @@ | |
| 301 | */ |
| 302 | int vfile_top_of_checkout(const char *zPath){ |
| 303 | char *zFile; |
| 304 | int fileFound = 0; |
| 305 | |
| 306 | zFile = mprintf("%s/_FOSSIL_", zPath); |
| 307 | fileFound = file_size(zFile)>=1024; |
| 308 | fossil_free(zFile); |
| 309 | if( !fileFound ){ |
| 310 | zFile = mprintf("%s/.fos", zPath); |
| 311 | fileFound = file_size(zFile)>=1024; |
| 312 | fossil_free(zFile); |
| 313 | } |
| 314 | return fileFound; |
| 315 | } |
| 316 |
+2
-2
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -301,15 +301,15 @@ | ||
| 301 | 301 | */ |
| 302 | 302 | int vfile_top_of_checkout(const char *zPath){ |
| 303 | 303 | char *zFile; |
| 304 | 304 | int fileFound = 0; |
| 305 | 305 | |
| 306 | - zFile = mprintf("%s/_FOSSIL_"); | |
| 306 | + zFile = mprintf("%s/_FOSSIL_", zPath); | |
| 307 | 307 | fileFound = file_size(zFile)>=1024; |
| 308 | 308 | fossil_free(zFile); |
| 309 | 309 | if( !fileFound ){ |
| 310 | - zFile = mprintf("%s/.fos"); | |
| 310 | + zFile = mprintf("%s/.fos", zPath); | |
| 311 | 311 | fileFound = file_size(zFile)>=1024; |
| 312 | 312 | fossil_free(zFile); |
| 313 | 313 | } |
| 314 | 314 | return fileFound; |
| 315 | 315 | } |
| 316 | 316 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -301,15 +301,15 @@ | |
| 301 | */ |
| 302 | int vfile_top_of_checkout(const char *zPath){ |
| 303 | char *zFile; |
| 304 | int fileFound = 0; |
| 305 | |
| 306 | zFile = mprintf("%s/_FOSSIL_"); |
| 307 | fileFound = file_size(zFile)>=1024; |
| 308 | fossil_free(zFile); |
| 309 | if( !fileFound ){ |
| 310 | zFile = mprintf("%s/.fos"); |
| 311 | fileFound = file_size(zFile)>=1024; |
| 312 | fossil_free(zFile); |
| 313 | } |
| 314 | return fileFound; |
| 315 | } |
| 316 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -301,15 +301,15 @@ | |
| 301 | */ |
| 302 | int vfile_top_of_checkout(const char *zPath){ |
| 303 | char *zFile; |
| 304 | int fileFound = 0; |
| 305 | |
| 306 | zFile = mprintf("%s/_FOSSIL_", zPath); |
| 307 | fileFound = file_size(zFile)>=1024; |
| 308 | fossil_free(zFile); |
| 309 | if( !fileFound ){ |
| 310 | zFile = mprintf("%s/.fos", zPath); |
| 311 | fileFound = file_size(zFile)>=1024; |
| 312 | fossil_free(zFile); |
| 313 | } |
| 314 | return fileFound; |
| 315 | } |
| 316 |