Age Owner Branch data TLA Line data Source code
1 : : /* src/interfaces/ecpg/preproc/util.c */
2 : :
3 : : #include "postgres_fe.h"
4 : :
5 : : #include <unistd.h>
6 : :
7 : : #include "preproc_extern.h"
8 : :
9 : : static void vmmerror(int error_code, enum errortype type, const char *error, va_list ap) pg_attribute_printf(3, 0);
10 : :
11 : :
12 : : /*
13 : : * Handle preprocessor errors and warnings
14 : : */
15 : : static void
379 tgl@sss.pgh.pa.us 16 :GIC 17 : vmmerror(int error_code, enum errortype type, const char *error, va_list ap)
17 : : {
18 : : /* localize the error message string */
19 : 17 : error = _(error);
20 : :
21 : 17 : fprintf(stderr, "%s:%d: ", input_filename, base_yylineno);
22 : :
23 [ + + - ]: 17 : switch (type)
24 : : {
25 : 6 : case ET_WARNING:
26 : 6 : fprintf(stderr, _("WARNING: "));
27 : 6 : break;
28 : 11 : case ET_ERROR:
29 : 11 : fprintf(stderr, _("ERROR: "));
30 : 11 : break;
31 : : }
32 : :
33 : 17 : vfprintf(stderr, error, ap);
34 : :
35 : 17 : fprintf(stderr, "\n");
36 : :
37 : : /* If appropriate, set error code to be inspected by ecpg.c */
38 [ + + - ]: 17 : switch (type)
39 : : {
40 : 6 : case ET_WARNING:
41 : 6 : break;
42 : 11 : case ET_ERROR:
43 : 11 : ret_value = error_code;
44 : 11 : break;
45 : : }
46 : 17 : }
47 : :
48 : : /* Report an error or warning */
49 : : void
50 : 16 : mmerror(int error_code, enum errortype type, const char *error,...)
51 : : {
52 : : va_list ap;
53 : :
54 : 16 : va_start(ap, error);
55 : 16 : vmmerror(error_code, type, error, ap);
56 : 16 : va_end(ap);
57 : 16 : }
58 : :
59 : : /* Report an error and abandon execution */
60 : : void
61 : 1 : mmfatal(int error_code, const char *error,...)
62 : : {
63 : : va_list ap;
64 : :
65 : 1 : va_start(ap, error);
66 : 1 : vmmerror(error_code, ET_ERROR, error, ap);
67 : 1 : va_end(ap);
68 : :
69 [ + - ]: 1 : if (base_yyin)
70 : 1 : fclose(base_yyin);
71 [ + - ]: 1 : if (base_yyout)
72 : 1 : fclose(base_yyout);
73 : :
74 [ + - - + ]: 1 : if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0)
379 tgl@sss.pgh.pa.us 75 :UIC 0 : fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
379 tgl@sss.pgh.pa.us 76 :GIC 1 : exit(error_code);
77 : : }
78 : :
79 : : /*
80 : : * Basic memory management support
81 : : */
82 : :
83 : : /* malloc + error check */
84 : : void *
85 : 28685 : mm_alloc(size_t size)
86 : : {
87 : 28685 : void *ptr = malloc(size);
88 : :
89 [ - + ]: 28685 : if (ptr == NULL)
379 tgl@sss.pgh.pa.us 90 :UIC 0 : mmfatal(OUT_OF_MEMORY, "out of memory");
91 : :
379 tgl@sss.pgh.pa.us 92 :GIC 28685 : return ptr;
93 : : }
94 : :
95 : : /* strdup + error check */
96 : : char *
97 : 6241 : mm_strdup(const char *string)
98 : : {
99 : 6241 : char *new = strdup(string);
100 : :
101 [ - + ]: 6241 : if (new == NULL)
379 tgl@sss.pgh.pa.us 102 :UIC 0 : mmfatal(OUT_OF_MEMORY, "out of memory");
103 : :
379 tgl@sss.pgh.pa.us 104 :GIC 6241 : return new;
105 : : }
106 : :
107 : :
108 : : /*
109 : : * "Local" memory management support
110 : : *
111 : : * These functions manage memory that is only needed for a short time
112 : : * (processing of one input statement) within the ecpg grammar.
113 : : * Data allocated with these is not meant to be freed separately;
114 : : * rather it's freed by calling reclaim_local_storage() at the end
115 : : * of each statement cycle.
116 : : */
117 : :
118 : : typedef struct loc_chunk
119 : : {
120 : : struct loc_chunk *next; /* list link */
121 : : unsigned int chunk_used; /* index of first unused byte in data[] */
122 : : unsigned int chunk_avail; /* # bytes still available in data[] */
123 : : char data[FLEXIBLE_ARRAY_MEMBER]; /* actual storage */
124 : : } loc_chunk;
125 : :
126 : : #define LOC_CHUNK_OVERHEAD MAXALIGN(offsetof(loc_chunk, data))
127 : : #define LOC_CHUNK_MIN_SIZE 8192
128 : :
129 : : /* Head of list of loc_chunks */
130 : : static loc_chunk *loc_chunks = NULL;
131 : :
132 : : /*
133 : : * Allocate local space of the requested size.
134 : : *
135 : : * Exits on OOM.
136 : : */
137 : : void *
138 : 89257 : loc_alloc(size_t size)
139 : : {
140 : : void *result;
141 : 89257 : loc_chunk *cur_chunk = loc_chunks;
142 : :
143 : : /* Ensure all allocations are adequately aligned */
144 : 89257 : size = MAXALIGN(size);
145 : :
146 : : /* Need a new chunk? */
147 [ + + + + ]: 89257 : if (cur_chunk == NULL || size > cur_chunk->chunk_avail)
148 : : {
149 : 24040 : size_t chunk_size = Max(size, LOC_CHUNK_MIN_SIZE);
150 : :
151 : 24040 : cur_chunk = mm_alloc(chunk_size + LOC_CHUNK_OVERHEAD);
152 : : /* Depending on alignment rules, we could waste a bit here */
153 : 24040 : cur_chunk->chunk_used = LOC_CHUNK_OVERHEAD - offsetof(loc_chunk, data);
154 : 24040 : cur_chunk->chunk_avail = chunk_size;
155 : : /* New chunk becomes the head of the list */
156 : 24040 : cur_chunk->next = loc_chunks;
157 : 24040 : loc_chunks = cur_chunk;
158 : : }
159 : :
160 : 89257 : result = cur_chunk->data + cur_chunk->chunk_used;
161 : 89257 : cur_chunk->chunk_used += size;
162 : 89257 : cur_chunk->chunk_avail -= size;
163 : 89257 : return result;
164 : : }
165 : :
166 : : /*
167 : : * Copy given string into local storage
168 : : */
169 : : char *
170 : 48179 : loc_strdup(const char *string)
171 : : {
172 : 48179 : char *result = loc_alloc(strlen(string) + 1);
173 : :
174 : 48179 : strcpy(result, string);
175 : 48179 : return result;
176 : : }
177 : :
178 : : /*
179 : : * Reclaim local storage when appropriate
180 : : */
181 : : void
182 : 23948 : reclaim_local_storage(void)
183 : : {
184 : : loc_chunk *cur_chunk,
185 : : *next_chunk;
186 : :
187 [ + + ]: 47920 : for (cur_chunk = loc_chunks; cur_chunk; cur_chunk = next_chunk)
188 : : {
189 : 23972 : next_chunk = cur_chunk->next;
190 : 23972 : free(cur_chunk);
191 : : }
192 : 23948 : loc_chunks = NULL;
193 : 23948 : }
194 : :
195 : :
196 : : /*
197 : : * String concatenation support routines. These return "local" (transient)
198 : : * storage.
199 : : */
200 : :
201 : : /*
202 : : * Concatenate 2 strings, inserting a space between them unless either is empty
203 : : */
204 : : char *
205 : 4929 : cat2_str(const char *str1, const char *str2)
206 : : {
207 : 4929 : char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 2);
208 : :
209 : 4929 : strcpy(res_str, str1);
210 [ + + + + ]: 4929 : if (strlen(str1) != 0 && strlen(str2) != 0)
211 : 3177 : strcat(res_str, " ");
212 : 4929 : strcat(res_str, str2);
213 : 4929 : return res_str;
214 : : }
215 : :
216 : : /*
217 : : * Concatenate N strings, inserting spaces between them unless they are empty
218 : : */
219 : : char *
220 : 1461 : cat_str(int count,...)
221 : : {
222 : : va_list args;
223 : : int i;
224 : : char *res_str;
225 : :
226 : 1461 : va_start(args, count);
227 : :
228 : 1461 : res_str = va_arg(args, char *);
229 : :
230 : : /* now add all other strings */
231 [ + + ]: 6070 : for (i = 1; i < count; i++)
232 : 4609 : res_str = cat2_str(res_str, va_arg(args, char *));
233 : :
234 : 1461 : va_end(args);
235 : :
236 : 1461 : return res_str;
237 : : }
238 : :
239 : : /*
240 : : * Concatenate 2 strings, with no space between
241 : : */
242 : : char *
243 : 50 : make2_str(const char *str1, const char *str2)
244 : : {
245 : 50 : char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 1);
246 : :
247 : 50 : strcpy(res_str, str1);
248 : 50 : strcat(res_str, str2);
249 : 50 : return res_str;
250 : : }
251 : :
252 : : /*
253 : : * Concatenate 3 strings, with no space between
254 : : */
255 : : char *
256 : 1854 : make3_str(const char *str1, const char *str2, const char *str3)
257 : : {
258 : 1854 : char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1);
259 : :
260 : 1854 : strcpy(res_str, str1);
261 : 1854 : strcat(res_str, str2);
262 : 1854 : strcat(res_str, str3);
263 : 1854 : return res_str;
264 : : }
|