Fossil SCM
Incomplete implementation of the "fossil grep" command.
Commit
c5a98aa0ba0692d1df4e9565cfee8ec584543370ba5e53e82bad57b35646a75f
Parent
d46491d6e66f9a8…
1 file changed
+94
-5
+94
-5
| --- src/regexp.c | ||
| +++ src/regexp.c | ||
| @@ -736,24 +736,56 @@ | ||
| 736 | 736 | return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, |
| 737 | 737 | re_sql_func, 0, 0); |
| 738 | 738 | } |
| 739 | 739 | |
| 740 | 740 | /* |
| 741 | -** Run a "grep" over a single file | |
| 741 | +** Run a "grep" over a single file read from disk. | |
| 742 | 742 | */ |
| 743 | -static void grep(ReCompiled *pRe, const char *zFile, FILE *in){ | |
| 743 | +static void grep_file(ReCompiled *pRe, const char *zFile, FILE *in){ | |
| 744 | 744 | int ln = 0; |
| 745 | 745 | int n; |
| 746 | 746 | char zLine[2000]; |
| 747 | 747 | while( fgets(zLine, sizeof(zLine), in) ){ |
| 748 | 748 | ln++; |
| 749 | 749 | n = (int)strlen(zLine); |
| 750 | 750 | while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--; |
| 751 | 751 | if( re_match(pRe, (const unsigned char*)zLine, n) ){ |
| 752 | - printf("%s:%d:%.*s\n", zFile, ln, n, zLine); | |
| 752 | + fossil_print("%s:%d:%.*s\n", zFile, ln, n, zLine); | |
| 753 | + } | |
| 754 | + } | |
| 755 | +} | |
| 756 | + | |
| 757 | +/* | |
| 758 | +** Flags for grep_buffer() | |
| 759 | +*/ | |
| 760 | +#define GREP_EXISTS 0x001 /* If any match, print only the name and stop */ | |
| 761 | + | |
| 762 | +/* | |
| 763 | +** Run a "grep" over a text file | |
| 764 | +*/ | |
| 765 | +static int grep_buffer( | |
| 766 | + ReCompiled *pRe, | |
| 767 | + const char *zName, | |
| 768 | + const char *z, | |
| 769 | + u32 flags | |
| 770 | +){ | |
| 771 | + int i, j, n, ln, cnt; | |
| 772 | + for(i=j=ln=cnt=0; z[i]; i=j+1){ | |
| 773 | + for(j=i; z[j] && z[j]!='\n'; j++){} | |
| 774 | + n = j - i; | |
| 775 | + if( z[j]=='\n' ) j++; | |
| 776 | + ln++; | |
| 777 | + if( re_match(pRe, (const unsigned char*)(z+i), j-i) ){ | |
| 778 | + cnt++; | |
| 779 | + if( flags & GREP_EXISTS ){ | |
| 780 | + fossil_print("%s\n", zName); | |
| 781 | + break; | |
| 782 | + } | |
| 783 | + fossil_print("%s:%d:%.*s\n", zName, ln, n, z+i); | |
| 753 | 784 | } |
| 754 | 785 | } |
| 786 | + return cnt; | |
| 755 | 787 | } |
| 756 | 788 | |
| 757 | 789 | /* |
| 758 | 790 | ** COMMAND: test-grep |
| 759 | 791 | ** |
| @@ -774,20 +806,77 @@ | ||
| 774 | 806 | usage("REGEXP [FILE...]"); |
| 775 | 807 | } |
| 776 | 808 | zErr = re_compile(&pRe, g.argv[2], ignoreCase); |
| 777 | 809 | if( zErr ) fossil_fatal("%s", zErr); |
| 778 | 810 | if( g.argc==3 ){ |
| 779 | - grep(pRe, "-", stdin); | |
| 811 | + grep_file(pRe, "-", stdin); | |
| 780 | 812 | }else{ |
| 781 | 813 | int i; |
| 782 | 814 | for(i=3; i<g.argc; i++){ |
| 783 | 815 | FILE *in = fossil_fopen(g.argv[i], "rb"); |
| 784 | 816 | if( in==0 ){ |
| 785 | 817 | fossil_warning("cannot open \"%s\"", g.argv[i]); |
| 786 | 818 | }else{ |
| 787 | - grep(pRe, g.argv[i], in); | |
| 819 | + grep_file(pRe, g.argv[i], in); | |
| 788 | 820 | fclose(in); |
| 789 | 821 | } |
| 790 | 822 | } |
| 791 | 823 | } |
| 792 | 824 | re_free(pRe); |
| 793 | 825 | } |
| 826 | + | |
| 827 | +/* | |
| 828 | +** COMMAND: grep | |
| 829 | +** | |
| 830 | +** Usage: %fossil grep [OPTIONS] PATTERN FILENAME|CHECKIN | |
| 831 | +** | |
| 832 | +** Run grep over all historic version of FILENAME or over all files | |
| 833 | +** in CHECKIN. | |
| 834 | +** | |
| 835 | +** Options: | |
| 836 | +** | |
| 837 | +** -i|--ignore-case Ignore case | |
| 838 | +** -l|--files-with-matches Print only filenames that match | |
| 839 | +** -v|--verbose Show each file as it is analyzed | |
| 840 | +*/ | |
| 841 | +void re_grep_cmd(void){ | |
| 842 | + u32 flags = 0; | |
| 843 | + int bVerbose = 0; | |
| 844 | + ReCompiled *pRe; | |
| 845 | + const char *zErr; | |
| 846 | + int ignoreCase = 0; | |
| 847 | + Blob fullName; | |
| 848 | + | |
| 849 | + if( find_option("ignore-case","i",0)!=0 ) ignoreCase = 1; | |
| 850 | + if( find_option("files-with-matches","l",0)!=0 ) flags |= GREP_EXISTS; | |
| 851 | + if( find_option("verbose","v",0)!=0 ) bVerbose = 1; | |
| 852 | + db_find_and_open_repository(0, 0); | |
| 853 | + verify_all_options(); | |
| 854 | + if( g.argc<3 ){ | |
| 855 | + usage("REGEXP FILENAME|CHECKIN"); | |
| 856 | + } | |
| 857 | + zErr = re_compile(&pRe, g.argv[2], ignoreCase); | |
| 858 | + if( zErr ) fossil_fatal("%s", zErr); | |
| 859 | + | |
| 860 | + if( file_tree_name(g.argv[3], &fullName, 0, 0) ){ | |
| 861 | + int fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", | |
| 862 | + blob_str(&fullName)); | |
| 863 | + Stmt q; | |
| 864 | + if( fnid==0 ){ | |
| 865 | + fossil_fatal("no such file: \"%s\"", blob_str(&fullName)); | |
| 866 | + } | |
| 867 | + add_content_sql_commands(g.db); | |
| 868 | + db_prepare(&q, | |
| 869 | + "SELECT content(uuid), substr(uuid,1,10)" | |
| 870 | + " FROM mlink, blob, event" | |
| 871 | + " WHERE mlink.mid=event.objid" | |
| 872 | + " AND mlink.fid=blob.rid" | |
| 873 | + " AND mlink.fnid=%d" | |
| 874 | + " ORDER BY event.mtime DESC", | |
| 875 | + fnid | |
| 876 | + ); | |
| 877 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 878 | + grep_buffer(pRe, db_column_text(&q,1), db_column_text(&q,0), flags); | |
| 879 | + } | |
| 880 | + db_finalize(&q); | |
| 881 | + } | |
| 882 | +} | |
| 794 | 883 |
| --- src/regexp.c | |
| +++ src/regexp.c | |
| @@ -736,24 +736,56 @@ | |
| 736 | return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, |
| 737 | re_sql_func, 0, 0); |
| 738 | } |
| 739 | |
| 740 | /* |
| 741 | ** Run a "grep" over a single file |
| 742 | */ |
| 743 | static void grep(ReCompiled *pRe, const char *zFile, FILE *in){ |
| 744 | int ln = 0; |
| 745 | int n; |
| 746 | char zLine[2000]; |
| 747 | while( fgets(zLine, sizeof(zLine), in) ){ |
| 748 | ln++; |
| 749 | n = (int)strlen(zLine); |
| 750 | while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--; |
| 751 | if( re_match(pRe, (const unsigned char*)zLine, n) ){ |
| 752 | printf("%s:%d:%.*s\n", zFile, ln, n, zLine); |
| 753 | } |
| 754 | } |
| 755 | } |
| 756 | |
| 757 | /* |
| 758 | ** COMMAND: test-grep |
| 759 | ** |
| @@ -774,20 +806,77 @@ | |
| 774 | usage("REGEXP [FILE...]"); |
| 775 | } |
| 776 | zErr = re_compile(&pRe, g.argv[2], ignoreCase); |
| 777 | if( zErr ) fossil_fatal("%s", zErr); |
| 778 | if( g.argc==3 ){ |
| 779 | grep(pRe, "-", stdin); |
| 780 | }else{ |
| 781 | int i; |
| 782 | for(i=3; i<g.argc; i++){ |
| 783 | FILE *in = fossil_fopen(g.argv[i], "rb"); |
| 784 | if( in==0 ){ |
| 785 | fossil_warning("cannot open \"%s\"", g.argv[i]); |
| 786 | }else{ |
| 787 | grep(pRe, g.argv[i], in); |
| 788 | fclose(in); |
| 789 | } |
| 790 | } |
| 791 | } |
| 792 | re_free(pRe); |
| 793 | } |
| 794 |
| --- src/regexp.c | |
| +++ src/regexp.c | |
| @@ -736,24 +736,56 @@ | |
| 736 | return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, |
| 737 | re_sql_func, 0, 0); |
| 738 | } |
| 739 | |
| 740 | /* |
| 741 | ** Run a "grep" over a single file read from disk. |
| 742 | */ |
| 743 | static void grep_file(ReCompiled *pRe, const char *zFile, FILE *in){ |
| 744 | int ln = 0; |
| 745 | int n; |
| 746 | char zLine[2000]; |
| 747 | while( fgets(zLine, sizeof(zLine), in) ){ |
| 748 | ln++; |
| 749 | n = (int)strlen(zLine); |
| 750 | while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--; |
| 751 | if( re_match(pRe, (const unsigned char*)zLine, n) ){ |
| 752 | fossil_print("%s:%d:%.*s\n", zFile, ln, n, zLine); |
| 753 | } |
| 754 | } |
| 755 | } |
| 756 | |
| 757 | /* |
| 758 | ** Flags for grep_buffer() |
| 759 | */ |
| 760 | #define GREP_EXISTS 0x001 /* If any match, print only the name and stop */ |
| 761 | |
| 762 | /* |
| 763 | ** Run a "grep" over a text file |
| 764 | */ |
| 765 | static int grep_buffer( |
| 766 | ReCompiled *pRe, |
| 767 | const char *zName, |
| 768 | const char *z, |
| 769 | u32 flags |
| 770 | ){ |
| 771 | int i, j, n, ln, cnt; |
| 772 | for(i=j=ln=cnt=0; z[i]; i=j+1){ |
| 773 | for(j=i; z[j] && z[j]!='\n'; j++){} |
| 774 | n = j - i; |
| 775 | if( z[j]=='\n' ) j++; |
| 776 | ln++; |
| 777 | if( re_match(pRe, (const unsigned char*)(z+i), j-i) ){ |
| 778 | cnt++; |
| 779 | if( flags & GREP_EXISTS ){ |
| 780 | fossil_print("%s\n", zName); |
| 781 | break; |
| 782 | } |
| 783 | fossil_print("%s:%d:%.*s\n", zName, ln, n, z+i); |
| 784 | } |
| 785 | } |
| 786 | return cnt; |
| 787 | } |
| 788 | |
| 789 | /* |
| 790 | ** COMMAND: test-grep |
| 791 | ** |
| @@ -774,20 +806,77 @@ | |
| 806 | usage("REGEXP [FILE...]"); |
| 807 | } |
| 808 | zErr = re_compile(&pRe, g.argv[2], ignoreCase); |
| 809 | if( zErr ) fossil_fatal("%s", zErr); |
| 810 | if( g.argc==3 ){ |
| 811 | grep_file(pRe, "-", stdin); |
| 812 | }else{ |
| 813 | int i; |
| 814 | for(i=3; i<g.argc; i++){ |
| 815 | FILE *in = fossil_fopen(g.argv[i], "rb"); |
| 816 | if( in==0 ){ |
| 817 | fossil_warning("cannot open \"%s\"", g.argv[i]); |
| 818 | }else{ |
| 819 | grep_file(pRe, g.argv[i], in); |
| 820 | fclose(in); |
| 821 | } |
| 822 | } |
| 823 | } |
| 824 | re_free(pRe); |
| 825 | } |
| 826 | |
| 827 | /* |
| 828 | ** COMMAND: grep |
| 829 | ** |
| 830 | ** Usage: %fossil grep [OPTIONS] PATTERN FILENAME|CHECKIN |
| 831 | ** |
| 832 | ** Run grep over all historic version of FILENAME or over all files |
| 833 | ** in CHECKIN. |
| 834 | ** |
| 835 | ** Options: |
| 836 | ** |
| 837 | ** -i|--ignore-case Ignore case |
| 838 | ** -l|--files-with-matches Print only filenames that match |
| 839 | ** -v|--verbose Show each file as it is analyzed |
| 840 | */ |
| 841 | void re_grep_cmd(void){ |
| 842 | u32 flags = 0; |
| 843 | int bVerbose = 0; |
| 844 | ReCompiled *pRe; |
| 845 | const char *zErr; |
| 846 | int ignoreCase = 0; |
| 847 | Blob fullName; |
| 848 | |
| 849 | if( find_option("ignore-case","i",0)!=0 ) ignoreCase = 1; |
| 850 | if( find_option("files-with-matches","l",0)!=0 ) flags |= GREP_EXISTS; |
| 851 | if( find_option("verbose","v",0)!=0 ) bVerbose = 1; |
| 852 | db_find_and_open_repository(0, 0); |
| 853 | verify_all_options(); |
| 854 | if( g.argc<3 ){ |
| 855 | usage("REGEXP FILENAME|CHECKIN"); |
| 856 | } |
| 857 | zErr = re_compile(&pRe, g.argv[2], ignoreCase); |
| 858 | if( zErr ) fossil_fatal("%s", zErr); |
| 859 | |
| 860 | if( file_tree_name(g.argv[3], &fullName, 0, 0) ){ |
| 861 | int fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", |
| 862 | blob_str(&fullName)); |
| 863 | Stmt q; |
| 864 | if( fnid==0 ){ |
| 865 | fossil_fatal("no such file: \"%s\"", blob_str(&fullName)); |
| 866 | } |
| 867 | add_content_sql_commands(g.db); |
| 868 | db_prepare(&q, |
| 869 | "SELECT content(uuid), substr(uuid,1,10)" |
| 870 | " FROM mlink, blob, event" |
| 871 | " WHERE mlink.mid=event.objid" |
| 872 | " AND mlink.fid=blob.rid" |
| 873 | " AND mlink.fnid=%d" |
| 874 | " ORDER BY event.mtime DESC", |
| 875 | fnid |
| 876 | ); |
| 877 | while( db_step(&q)==SQLITE_ROW ){ |
| 878 | grep_buffer(pRe, db_column_text(&q,1), db_column_text(&q,0), flags); |
| 879 | } |
| 880 | db_finalize(&q); |
| 881 | } |
| 882 | } |
| 883 |