xref: /lighttpd1.4/src/data_config.c (revision e11f72b1)
1 #include "first.h"
2 
3 #include "array.h"
4 #include "configfile.h"
5 
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 
10 #ifdef HAVE_PCRE_H
11 #include <pcre.h>
12 #endif
13 
14 __attribute_cold__
15 static data_unset *data_config_copy(const data_unset *s) {
16 	data_config *src = (data_config *)s;
17 	data_config *ds = data_config_init();
18 
19 	ds->comp = src->comp;
20 	if (!buffer_is_empty(&src->key)) buffer_copy_buffer(&ds->key, &src->key);
21 	buffer_copy_buffer(ds->comp_tag, src->comp_tag);
22 	buffer_copy_buffer(ds->comp_key, src->comp_key);
23 	array_copy_array(ds->value, src->value);
24 	return (data_unset *)ds;
25 }
26 
27 __attribute_cold__
28 static void data_config_free(data_unset *d) {
29 	data_config *ds = (data_config *)d;
30 
31 	free(ds->key.ptr);
32 	buffer_free(ds->comp_tag);
33 	buffer_free(ds->comp_key);
34 
35 	array_free(ds->value);
36 	vector_config_weak_clear(&ds->children);
37 
38 	free(ds->string.ptr);
39 #ifdef HAVE_PCRE_H
40 	if (ds->regex) pcre_free(ds->regex);
41 	if (ds->regex_study) pcre_free(ds->regex_study);
42 #endif
43 
44 	free(d);
45 }
46 
47 __attribute_cold__
48 static int data_config_insert_dup(data_unset *dst, data_unset *src) {
49 	UNUSED(dst);
50 
51 	src->fn->free(src);
52 
53 	return 0;
54 }
55 
56 __attribute_cold__
57 static void data_config_print(const data_unset *d, int depth) {
58 	data_config *ds = (data_config *)d;
59 	array *a = (array *)ds->value;
60 	size_t i;
61 	size_t maxlen;
62 
63 	if (0 == ds->context_ndx) {
64 		fprintf(stdout, "config {\n");
65 	}
66 	else {
67 		if (ds->cond != CONFIG_COND_ELSE) {
68 			fprintf(stdout, "$%s %s \"%s\" {\n",
69 					ds->comp_key->ptr, ds->op, ds->string.ptr);
70 		} else {
71 			fprintf(stdout, "{\n");
72 		}
73 		array_print_indent(depth + 1);
74 		fprintf(stdout, "# block %d\n", ds->context_ndx);
75 	}
76 	depth ++;
77 
78 	maxlen = array_get_max_key_length(a);
79 	for (i = 0; i < a->used; i ++) {
80 		data_unset *du = a->data[i];
81 		size_t len = buffer_string_length(&du->key);
82 		size_t j;
83 
84 		array_print_indent(depth);
85 		fprintf(stdout, "%s", du->key.ptr);
86 		for (j = maxlen - len; j > 0; j --) {
87 			fprintf(stdout, " ");
88 		}
89 		fprintf(stdout, " = ");
90 		du->fn->print(du, depth);
91 		fprintf(stdout, "\n");
92 	}
93 
94 	fprintf(stdout, "\n");
95 	for (i = 0; i < ds->children.used; i ++) {
96 		data_config *dc = ds->children.data[i];
97 
98 		/* only the 1st block of chaining */
99 		if (NULL == dc->prev) {
100 			fprintf(stdout, "\n");
101 			array_print_indent(depth);
102 			dc->fn->print((data_unset *) dc, depth);
103 			fprintf(stdout, "\n");
104 		}
105 	}
106 
107 	depth --;
108 	array_print_indent(depth);
109 	fprintf(stdout, "}");
110 	if (0 != ds->context_ndx) {
111 		if (ds->cond != CONFIG_COND_ELSE) {
112 			fprintf(stdout, " # end of $%s %s \"%s\"",
113 					ds->comp_key->ptr, ds->op, ds->string.ptr);
114 		} else {
115 			fprintf(stdout, " # end of else");
116 		}
117 	}
118 
119 	if (ds->next) {
120 		fprintf(stdout, "\n");
121 		array_print_indent(depth);
122 		fprintf(stdout, "else ");
123 		ds->next->fn->print((data_unset *)ds->next, depth);
124 	}
125 }
126 
127 data_config *data_config_init(void) {
128 	static const struct data_methods fn = {
129 		data_config_copy,
130 		data_config_free,
131 		data_config_insert_dup,
132 		data_config_print,
133 	};
134 	data_config *ds;
135 
136 	ds = calloc(1, sizeof(*ds));
137 
138 	ds->comp_tag = buffer_init();
139 	ds->comp_key = buffer_init();
140 	ds->value = array_init(4);
141 	vector_config_weak_init(&ds->children);
142 
143 	ds->type = TYPE_CONFIG;
144 	ds->fn = &fn;
145 
146 	return ds;
147 }
148 
149 int data_config_pcre_compile(data_config *dc) {
150 #ifdef HAVE_PCRE_H
151     /* (use fprintf() on error, as this is called from configparser.y) */
152     const char *errptr;
153     int erroff, captures;
154 
155     if (dc->regex) pcre_free(dc->regex);
156     if (dc->regex_study) pcre_free(dc->regex_study);
157 
158     dc->regex = pcre_compile(dc->string.ptr, 0, &errptr, &erroff, NULL);
159     if (NULL == dc->regex) {
160         fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
161                 dc->string.ptr, errptr, erroff);
162         return 0;
163     }
164 
165     dc->regex_study = pcre_study(dc->regex, 0, &errptr);
166     if (NULL == dc->regex_study && errptr != NULL) {
167         fprintf(stderr, "studying regex failed: %s -> %s\n",
168                 dc->string.ptr, errptr);
169         return 0;
170     }
171 
172     erroff = pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT,
173                            &captures);
174     if (0 != erroff) {
175         fprintf(stderr, "getting capture count for regex failed: %s\n",
176                 dc->string.ptr);
177         return 0;
178     } else if (captures > 9) {
179         fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n",
180                 dc->string.ptr);
181         return 0;
182     }
183     return 1;
184 #else
185     fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
186                     "(perhaps just a missing pcre-devel package ?) \n",
187                     dc->comp_key->ptr, dc->comp_tag->ptr);
188     return 0;
189 #endif
190 }
191