summaryrefslogtreecommitdiff
path: root/grep.h
blob: bdcadce61b8027adc760cd6e7fc51aa4e94c3d06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#ifndef GREP_H
#define GREP_H
#include "color.h"
#ifdef USE_LIBPCRE2
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 36) || PCRE2_MAJOR >= 11
#define GIT_PCRE2_VERSION_10_36_OR_HIGHER
#endif
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 34) || PCRE2_MAJOR >= 11
#define GIT_PCRE2_VERSION_10_34_OR_HIGHER
#endif
#else
typedef int pcre2_code;
typedef int pcre2_match_data;
typedef int pcre2_compile_context;
typedef int pcre2_general_context;
#endif
#ifndef PCRE2_MATCH_INVALID_UTF
/* PCRE2_MATCH_* dummy also with !USE_LIBPCRE2, for test-pcre2-config.c */
#define PCRE2_MATCH_INVALID_UTF 0
#endif
#include "thread-utils.h"
#include "userdiff.h"

struct repository;

enum grep_pat_token {
	GREP_PATTERN,
	GREP_PATTERN_HEAD,
	GREP_PATTERN_BODY,
	GREP_AND,
	GREP_OPEN_PAREN,
	GREP_CLOSE_PAREN,
	GREP_NOT,
	GREP_OR
};

enum grep_context {
	GREP_CONTEXT_HEAD,
	GREP_CONTEXT_BODY
};

enum grep_header_field {
	GREP_HEADER_FIELD_MIN = 0,
	GREP_HEADER_AUTHOR = GREP_HEADER_FIELD_MIN,
	GREP_HEADER_COMMITTER,
	GREP_HEADER_REFLOG,

	/* Must be at the end of the enum */
	GREP_HEADER_FIELD_MAX
};

enum grep_color {
	GREP_COLOR_CONTEXT,
	GREP_COLOR_FILENAME,
	GREP_COLOR_FUNCTION,
	GREP_COLOR_LINENO,
	GREP_COLOR_COLUMNNO,
	GREP_COLOR_MATCH_CONTEXT,
	GREP_COLOR_MATCH_SELECTED,
	GREP_COLOR_SELECTED,
	GREP_COLOR_SEP,
	NR_GREP_COLORS
};

struct grep_pat {
	struct grep_pat *next;
	const char *origin;
	int no;
	enum grep_pat_token token;
	char *pattern;
	size_t patternlen;
	enum grep_header_field field;
	regex_t regexp;
	pcre2_code *pcre2_pattern;
	pcre2_match_data *pcre2_match_data;
	pcre2_compile_context *pcre2_compile_context;
	pcre2_general_context *pcre2_general_context;
	const uint8_t *pcre2_tables;
	uint32_t pcre2_jit_on;
	unsigned fixed:1;
	unsigned is_fixed:1;
	unsigned ignore_case:1;
	unsigned word_regexp:1;
};

enum grep_expr_node {
	GREP_NODE_ATOM,
	GREP_NODE_NOT,
	GREP_NODE_AND,
	GREP_NODE_TRUE,
	GREP_NODE_OR
};

enum grep_pattern_type {
	GREP_PATTERN_TYPE_UNSPECIFIED = 0,
	GREP_PATTERN_TYPE_BRE,
	GREP_PATTERN_TYPE_ERE,
	GREP_PATTERN_TYPE_FIXED,
	GREP_PATTERN_TYPE_PCRE
};

struct grep_expr {
	enum grep_expr_node node;
	unsigned hit;
	union {
		struct grep_pat *atom;
		struct grep_expr *unary;
		struct {
			struct grep_expr *left;
			struct grep_expr *right;
		} binary;
	} u;
};

struct grep_opt {
	struct grep_pat *pattern_list;
	struct grep_pat **pattern_tail;
	struct grep_pat *header_list;
	struct grep_pat **header_tail;
	struct grep_expr *pattern_expression;

	/*
	 * NEEDSWORK: See if we can remove this field, because the repository
	 * should probably be per-source. That is, grep.c functions using this
	 * field should probably start using "repo" in "struct grep_source"
	 * instead.
	 *
	 * This is potentially the cause of at least one bug - "git grep"
	 * using the textconv attributes from the superproject on the
	 * submodules. See the failing "git grep --textconv" tests in
	 * t7814-grep-recurse-submodules.sh for more information.
	 */
	struct repository *repo;

	int linenum;
	int columnnum;
	int invert;
	int ignore_case;
	int status_only;
	int name_only;
	int unmatch_name_only;
	int count;
	int word_regexp;
	int all_match;
	int no_body_match;
	int body_hit;
#define GREP_BINARY_DEFAULT	0
#define GREP_BINARY_NOMATCH	1
#define GREP_BINARY_TEXT	2
	int binary;
	int allow_textconv;
	int extended;
	int use_reflog_filter;
	int relative;
	int pathname;
	int null_following_name;
	int only_matching;
	int color;
	int max_depth;
	int funcname;
	int funcbody;
	int extended_regexp_option;
	enum grep_pattern_type pattern_type_option;
	int ignore_locale;
	char colors[NR_GREP_COLORS][COLOR_MAXLEN];
	unsigned pre_context;
	unsigned post_context;
	unsigned last_shown;
	int show_hunk_mark;
	int file_break;
	int heading;
	int max_count;
	void *priv;

	void (*output)(struct grep_opt *opt, const void *data, size_t size);
	void *output_priv;
};

#define GREP_OPT_INIT { \
	.relative = 1, \
	.pathname = 1, \
	.max_depth = -1, \
	.max_count = -1, \
	.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \
	.colors = { \
		[GREP_COLOR_CONTEXT] = "", \
		[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \
		[GREP_COLOR_FUNCTION] = "", \
		[GREP_COLOR_LINENO] = GIT_COLOR_GREEN, \
		[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN, \
		[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \
		[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \
		[GREP_COLOR_SELECTED] = "", \
		[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \
	}, \
	.only_matching = 0, \
	.color = -1, \
	.output = std_output, \
}

int grep_config(const char *var, const char *value, void *);
void grep_init(struct grep_opt *, struct repository *repo);

void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
void compile_grep_patterns(struct grep_opt *opt);
void free_grep_patterns(struct grep_opt *opt);
int grep_buffer(struct grep_opt *opt, const char *buf, unsigned long size);

/* The field parameter is only used to filter header patterns
 * (where appropriate). If filtering isn't desirable
 * GREP_HEADER_FIELD_MAX should be supplied.
 */
int grep_next_match(struct grep_opt *opt,
		    const char *bol, const char *eol,
		    enum grep_context ctx, regmatch_t *pmatch,
		    enum grep_header_field field, int eflags);

struct grep_source {
	char *name;

	enum grep_source_type {
		GREP_SOURCE_OID,
		GREP_SOURCE_FILE,
		GREP_SOURCE_BUF,
	} type;
	void *identifier;
	struct repository *repo; /* if GREP_SOURCE_OID */

	const char *buf;
	unsigned long size;

	char *path; /* for attribute lookups */
	struct userdiff_driver *driver;
};

void grep_source_init_file(struct grep_source *gs, const char *name,
			   const char *path);
void grep_source_init_oid(struct grep_source *gs, const char *name,
			  const char *path, const struct object_id *oid,
			  struct repository *repo);
void grep_source_clear_data(struct grep_source *gs);
void grep_source_clear(struct grep_source *gs);
void grep_source_load_driver(struct grep_source *gs,
			     struct index_state *istate);


int grep_source(struct grep_opt *opt, struct grep_source *gs);

struct grep_opt *grep_opt_dup(const struct grep_opt *opt);

/*
 * Mutex used around access to the attributes machinery if
 * opt->use_threads.  Must be initialized/destroyed by callers!
 */
extern int grep_use_locks;
extern pthread_mutex_t grep_attr_mutex;

#endif