]> git.proxmox.com Git - libgit2.git/blame - src/filter.c
filter: Apply filters before writing a file to the ODB
[libgit2.git] / src / filter.c
CommitLineData
44b1ff4c
VM
1/*
2 * Copyright (C) 2009-2012 the libgit2 contributors
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8#include "common.h"
9#include "fileops.h"
10#include "hash.h"
11#include "filter.h"
12
13/* Fresh from Core Git. I wonder what we could use this for... */
14void git_text__stat(git_text_stats *stats, git_buf *text)
15{
16 size_t i;
17
18 memset(stats, 0, sizeof(*stats));
19
20 for (i = 0; i < text->size; i++) {
21 unsigned char c = text->ptr[i];
22
23 if (c == '\r') {
24 stats->cr++;
25
26 if (i + 1 < text->size && text->ptr[i + 1] == '\n')
27 stats->crlf++;
28
29 continue;
30 }
31
32 if (c == '\n') {
33 stats->lf++;
34 continue;
35 }
36
37 if (c == 127)
38 /* DEL */
39 stats->nonprintable++;
40
41 else if (c < 32) {
42 switch (c) {
43 /* BS, HT, ESC and FF */
44 case '\b': case '\t': case '\033': case '\014':
45 stats->printable++;
46 break;
47 case 0:
48 stats->nul++;
49 /* fall through */
50 default:
51 stats->nonprintable++;
52 }
53 }
54 else
55 stats->printable++;
56 }
57
58 /* If file ends with EOF then don't count this EOF as non-printable. */
59 if (text->size >= 1 && text->ptr[text->size - 1] == '\032')
60 stats->nonprintable--;
61}
62
63/*
64 * Fresh from Core Git
65 */
66int git_text__is_binary(git_text_stats *stats)
67{
68 if (stats->nul)
69 return 1;
70
71 if ((stats->printable >> 7) < stats->nonprintable)
72 return 1;
73 /*
74 * Other heuristics? Average line length might be relevant,
75 * as might LF vs CR vs CRLF counts..
76 *
77 * NOTE! It might be normal to have a low ratio of CRLF to LF
78 * (somebody starts with a LF-only file and edits it with an editor
79 * that adds CRLF only to lines that are added..). But do we
80 * want to support CR-only? Probably not.
81 */
82 return 0;
83}
84
85int git_filter__load_for_file(git_vector *filters, git_repository *repo, const char *full_path, int mode)
86{
87 /* We don't load any filters yet. HAHA */
88 return 0;
89}
90
91int git_filter__apply(git_buf *dest, git_buf *source, git_vector *filters, const char *filename)
92{
93 unsigned int src, dst, i;
94 git_buf *dbuffer[2];
95
96 dbuffer[0] = source;
97 dbuffer[1] = dest;
98
99 src = 0;
100
101 /* Pre-grow the destination buffer to more or less the size
102 * we expect it to have */
103 if (git_buf_grow(dest, source->size) < 0)
104 return GIT_ENOMEM;
105
106 for (i = 0; i < filters->length; ++i) {
107 git_filter_cb filter = git_vector_get(filters, i);
108 dst = (src + 1) % 2;
109
110 git_buf_clear(dbuffer[dst]);
111
112 /* Apply the filter, from dbuffer[src] to dbuffer[dst];
113 * if the filtering is canceled by the user mid-filter,
114 * we skip to the next filter without changing the source
115 * of the double buffering (so that the text goes through
116 * cleanly).
117 */
118 if (filter(dbuffer[dst], dbuffer[src], filename) == 0) {
119 src = (src + 1) % 2;
120 }
121
122 if (git_buf_oom(dbuffer[dst]))
123 return GIT_ENOMEM;
124 }
125
126 /* Ensure that the output ends up in dbuffer[1] (i.e. the dest) */
127 if (dst != 1) {
128 git_buf_swap(dest, source);
129 }
130
131 return GIT_SUCCESS;
132}