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
16 0 : vmmerror(int error_code, enum errortype type, const char *error, va_list ap)
17 : {
18 : /* localize the error message string */
19 0 : error = _(error);
20 :
21 0 : fprintf(stderr, "%s:%d: ", input_filename, base_yylineno);
22 :
23 0 : switch (type)
24 : {
25 0 : case ET_WARNING:
26 0 : fprintf(stderr, _("WARNING: "));
27 0 : break;
28 0 : case ET_ERROR:
29 0 : fprintf(stderr, _("ERROR: "));
30 0 : break;
31 : }
32 :
33 0 : vfprintf(stderr, error, ap);
34 :
35 0 : fprintf(stderr, "\n");
36 :
37 : /* If appropriate, set error code to be inspected by ecpg.c */
38 0 : switch (type)
39 : {
40 0 : case ET_WARNING:
41 0 : break;
42 0 : case ET_ERROR:
43 0 : ret_value = error_code;
44 0 : break;
45 : }
46 0 : }
47 :
48 : /* Report an error or warning */
49 : void
50 0 : mmerror(int error_code, enum errortype type, const char *error,...)
51 : {
52 : va_list ap;
53 :
54 0 : va_start(ap, error);
55 0 : vmmerror(error_code, type, error, ap);
56 0 : va_end(ap);
57 0 : }
58 :
59 : /* Report an error and abandon execution */
60 : void
61 0 : mmfatal(int error_code, const char *error,...)
62 : {
63 : va_list ap;
64 :
65 0 : va_start(ap, error);
66 0 : vmmerror(error_code, ET_ERROR, error, ap);
67 0 : va_end(ap);
68 :
69 0 : if (base_yyin)
70 0 : fclose(base_yyin);
71 0 : if (base_yyout)
72 0 : fclose(base_yyout);
73 :
74 0 : if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0)
75 0 : fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
76 0 : exit(error_code);
77 : }
78 :
79 : /*
80 : * Basic memory management support
81 : */
82 :
83 : /* malloc + error check */
84 : void *
85 57016 : mm_alloc(size_t size)
86 : {
87 57016 : void *ptr = malloc(size);
88 :
89 57016 : if (ptr == NULL)
90 0 : mmfatal(OUT_OF_MEMORY, "out of memory");
91 :
92 57016 : return ptr;
93 : }
94 :
95 : /* strdup + error check */
96 : char *
97 37990 : mm_strdup(const char *string)
98 : {
99 37990 : char *new = strdup(string);
100 :
101 37990 : if (new == NULL)
102 0 : mmfatal(OUT_OF_MEMORY, "out of memory");
103 :
104 37990 : 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 152664 : loc_alloc(size_t size)
139 : {
140 : void *result;
141 152664 : loc_chunk *cur_chunk = loc_chunks;
142 :
143 : /* Ensure all allocations are adequately aligned */
144 152664 : size = MAXALIGN(size);
145 :
146 : /* Need a new chunk? */
147 152664 : if (cur_chunk == NULL || size > cur_chunk->chunk_avail)
148 : {
149 47906 : size_t chunk_size = Max(size, LOC_CHUNK_MIN_SIZE);
150 :
151 47906 : cur_chunk = mm_alloc(chunk_size + LOC_CHUNK_OVERHEAD);
152 : /* Depending on alignment rules, we could waste a bit here */
153 47906 : cur_chunk->chunk_used = LOC_CHUNK_OVERHEAD - offsetof(loc_chunk, data);
154 47906 : cur_chunk->chunk_avail = chunk_size;
155 : /* New chunk becomes the head of the list */
156 47906 : cur_chunk->next = loc_chunks;
157 47906 : loc_chunks = cur_chunk;
158 : }
159 :
160 152664 : result = cur_chunk->data + cur_chunk->chunk_used;
161 152664 : cur_chunk->chunk_used += size;
162 152664 : cur_chunk->chunk_avail -= size;
163 152664 : return result;
164 : }
165 :
166 : /*
167 : * Copy given string into local storage
168 : */
169 : char *
170 71700 : loc_strdup(const char *string)
171 : {
172 71700 : char *result = loc_alloc(strlen(string) + 1);
173 :
174 71700 : strcpy(result, string);
175 71700 : return result;
176 : }
177 :
178 : /*
179 : * Reclaim local storage when appropriate
180 : */
181 : void
182 47748 : reclaim_local_storage(void)
183 : {
184 : loc_chunk *cur_chunk,
185 : *next_chunk;
186 :
187 95522 : for (cur_chunk = loc_chunks; cur_chunk; cur_chunk = next_chunk)
188 : {
189 47774 : next_chunk = cur_chunk->next;
190 47774 : free(cur_chunk);
191 : }
192 47748 : loc_chunks = NULL;
193 47748 : }
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 9570 : cat2_str(const char *str1, const char *str2)
206 : {
207 9570 : char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 2);
208 :
209 9570 : strcpy(res_str, str1);
210 9570 : if (strlen(str1) != 0 && strlen(str2) != 0)
211 6158 : strcat(res_str, " ");
212 9570 : strcat(res_str, str2);
213 9570 : return res_str;
214 : }
215 :
216 : /*
217 : * Concatenate N strings, inserting spaces between them unless they are empty
218 : */
219 : char *
220 2844 : cat_str(int count,...)
221 : {
222 : va_list args;
223 : int i;
224 : char *res_str;
225 :
226 2844 : va_start(args, count);
227 :
228 2844 : res_str = va_arg(args, char *);
229 :
230 : /* now add all other strings */
231 11784 : for (i = 1; i < count; i++)
232 8940 : res_str = cat2_str(res_str, va_arg(args, char *));
233 :
234 2844 : va_end(args);
235 :
236 2844 : return res_str;
237 : }
238 :
239 : /*
240 : * Concatenate 2 strings, with no space between
241 : */
242 : char *
243 100 : make2_str(const char *str1, const char *str2)
244 : {
245 100 : char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 1);
246 :
247 100 : strcpy(res_str, str1);
248 100 : strcat(res_str, str2);
249 100 : return res_str;
250 : }
251 :
252 : /*
253 : * Concatenate 3 strings, with no space between
254 : */
255 : char *
256 3296 : make3_str(const char *str1, const char *str2, const char *str3)
257 : {
258 3296 : char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1);
259 :
260 3296 : strcpy(res_str, str1);
261 3296 : strcat(res_str, str2);
262 3296 : strcat(res_str, str3);
263 3296 : return res_str;
264 : }
|