streaming filter: ident filter
Add support for "ident" filter on the output codepath. This does not work with lf-to-crlf filter together (yet). Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
May 20, 2011 at 18:28 UTC
b84c7839170ab35342d4ff098083c780075f015a
1 file changed
+169
-8
convert.c
+169
-8
@@ -872,6 +872,10 @@ int is_null_stream_filter(struct stream_filter *filter)
872
return filter == &null_filter_singleton;
873
}
874
875
+
876
+/*
877
+ * LF-to-CRLF filter
878
+ */
879
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
880
const char *input, size_t *isize_p,
881
char *output, size_t *osize_p)
@@ -909,6 +913,151 @@ static struct stream_filter lf_to_crlf_filter_singleton = {
913
&lf_to_crlf_vtbl,
914
};
915
916
+
917
+/*
918
+ * ident filter
919
+ */
920
+#define IDENT_DRAINING (-1)
921
+#define IDENT_SKIPPING (-2)
922
+struct ident_filter {
923
+ struct stream_filter filter;
924
+ struct strbuf left;
925
+ int state;
926
+ char ident[45]; /* ": x40 $" */
927
+};
928
+
929
+static int is_foreign_ident(const char *str)
930
+{
931
+ int i;
932
+
933
+ if (prefixcmp(str, "$Id: "))
934
+ return 0;
935
+ for (i = 5; str[i]; i++) {
936
+ if (isspace(str[i]) && str[i+1] != '$')
937
+ return 1;
938
+ }
939
+ return 0;
940
+}
941
+
942
+static void ident_drain(struct ident_filter *ident, char **output_p, size_t *osize_p)
943
+{
944
+ size_t to_drain = ident->left.len;
945
+
946
+ if (*osize_p < to_drain)
947
+ to_drain = *osize_p;
948
+ if (to_drain) {
949
+ memcpy(*output_p, ident->left.buf, to_drain);
950
+ strbuf_remove(&ident->left, 0, to_drain);
951
+ *output_p += to_drain;
952
+ *osize_p -= to_drain;
953
+ }
954
+ if (!ident->left.len)
955
+ ident->state = 0;
956
+}
957
+
958
+static int ident_filter_fn(struct stream_filter *filter,
959
+ const char *input, size_t *isize_p,
960
+ char *output, size_t *osize_p)
961
+{
962
+ struct ident_filter *ident = (struct ident_filter *)filter;
963
+ static const char head[] = "$Id";
964
+
965
+ if (!input) {
966
+ /* drain upon eof */
967
+ switch (ident->state) {
968
+ default:
969
+ strbuf_add(&ident->left, head, ident->state);
970
+ case IDENT_SKIPPING:
971
+ /* fallthru */
972
+ case IDENT_DRAINING:
973
+ ident_drain(ident, &output, osize_p);
974
+ }
975
+ return 0;
976
+ }
977
+
978
+ while (*isize_p || (ident->state == IDENT_DRAINING)) {
979
+ int ch;
980
+
981
+ if (ident->state == IDENT_DRAINING) {
982
+ ident_drain(ident, &output, osize_p);
983
+ if (!*osize_p)
984
+ break;
985
+ continue;
986
+ }
987
+
988
+ ch = *(input++);
989
+ (*isize_p)--;
990
+
991
+ if (ident->state == IDENT_SKIPPING) {
992
+ /*
993
+ * Skipping until '$' or LF, but keeping them
994
+ * in case it is a foreign ident.
995
+ */
996
+ strbuf_addch(&ident->left, ch);
997
+ if (ch != '\n' && ch != '$')
998
+ continue;
999
+ if (ch == '$' && !is_foreign_ident(ident->left.buf)) {
1000
+ strbuf_setlen(&ident->left, sizeof(head) - 1);
1001
+ strbuf_addstr(&ident->left, ident->ident);
1002
+ }
1003
+ ident->state = IDENT_DRAINING;
1004
+ continue;
1005
+ }
1006
+
1007
+ if (ident->state < sizeof(head) &&
1008
+ head[ident->state] == ch) {
1009
+ ident->state++;
1010
+ continue;
1011
+ }
1012
+
1013
+ if (ident->state)
1014
+ strbuf_add(&ident->left, head, ident->state);
1015
+ if (ident->state == sizeof(head) - 1) {
1016
+ if (ch != ':' && ch != '$') {
1017
+ strbuf_addch(&ident->left, ch);
1018
+ ident->state = 0;
1019
+ continue;
1020
+ }
1021
+
1022
+ if (ch == ':') {
1023
+ strbuf_addch(&ident->left, ch);
1024
+ ident->state = IDENT_SKIPPING;
1025
+ } else {
1026
+ strbuf_addstr(&ident->left, ident->ident);
1027
+ ident->state = IDENT_DRAINING;
1028
+ }
1029
+ continue;
1030
+ }
1031
+
1032
+ strbuf_addch(&ident->left, ch);
1033
+ ident->state = IDENT_DRAINING;
1034
+ }
1035
+ return 0;
1036
+}
1037
+
1038
+static void ident_free_fn(struct stream_filter *filter)
1039
+{
1040
+ struct ident_filter *ident = (struct ident_filter *)filter;
1041
+ strbuf_release(&ident->left);
1042
+ free(filter);
1043
+}
1044
+
1045
+static struct stream_filter_vtbl ident_vtbl = {
1046
+ ident_filter_fn,
1047
+ ident_free_fn,
1048
+};
1049
+
1050
+static struct stream_filter *ident_filter(const unsigned char *sha1)
1051
+{
1052
+ struct ident_filter *ident = xmalloc(sizeof(*ident));
1053
+
1054
+ sprintf(ident->ident, ": %s $", sha1_to_hex(sha1));
1055
+ strbuf_init(&ident->left, 0);
1056
+ ident->filter.vtbl = &ident_vtbl;
1057
+ ident->state = 0;
1058
+ return (struct stream_filter *)ident;
1059
+}
1060
+
1061
/*
1062
* Return an appropriately constructed filter for the path, or NULL if
1063
* the contents cannot be filtered without reading the whole thing
@@ -921,23 +1070,35 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
1070
{
1071
struct conv_attrs ca;
1072
enum crlf_action crlf_action;
1073
+ struct stream_filter *filter = NULL;
1074
1075
convert_attrs(&ca, path);
1076
927
- if (ca.ident ||
928
- (ca.drv && (ca.drv->smudge || ca.drv->clean)))
929
- return NULL;
1077
+ if (ca.drv && (ca.drv->smudge || ca.drv->clean))
1078
+ return filter;
1079
+
1080
+ if (ca.ident)
1081
+ filter = ident_filter(sha1);
1082
1083
crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
1084
+
1085
if ((crlf_action == CRLF_BINARY) || (crlf_action == CRLF_INPUT) ||
933
- (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE))
1086
+ (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE)) {
1087
+ if (filter) {
1088
+ free_stream_filter(filter);
1089
+ return NULL;
1090
+ }
1091
return &null_filter_singleton;
935
-
936
- if (output_eol(crlf_action) == EOL_CRLF &&
937
- !(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
1092
+ } else if (output_eol(crlf_action) == EOL_CRLF &&
1093
+ !(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS)) {
1094
+ if (filter) {
1095
+ free_stream_filter(filter);
1096
+ return NULL;
1097
+ }
1098
return &lf_to_crlf_filter_singleton;
1099
+ }
1100
940
- return NULL;
1101
+ return filter;
1102
}
1103
1104
void free_stream_filter(struct stream_filter *filter)