btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / bin / rc / compile.cpp
blob86993024aa25919bf4dcccaefb03524a019ad2ac
1 /*
2 * Copyright (c) 2003 Matthijs Hollemans
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
23 #include <Entry.h>
24 #include <File.h>
25 #include <Path.h>
27 #include <setjmp.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
33 #include "rdef.h"
34 #include "compile.h"
35 #include "private.h"
36 #include "parser.hpp"
38 char lexfile[B_PATH_NAME_LENGTH];
40 static BEntry entry;
41 static BFile file;
42 BResources rsrc;
43 const char* rsrc_file;
45 static jmp_buf abort_jmp; // for aborting compilation
47 // When it encounters an error, the parser immediately aborts (we don't try
48 // error recovery). But its parse stack may still contain malloc'ed objects.
49 // We keep track of these memory blocks in the mem_list, so we can properly
50 // free them in case of an error (which is the polite thing to do since we
51 // are a shared library). If the compilation was successful, then mem_list
52 // should be empty. In DEBUG mode we dump some statistics to verify that the
53 // parser properly frees up objects when it is done with them.
55 #ifdef DEBUG
56 struct mem_t {
57 void* ptr;
58 char* file;
59 int32 line;
62 typedef std::list<mem_t> mem_list_t;
63 typedef mem_list_t::iterator mem_iter_t;
65 static mem_list_t mem_list;
66 #else
67 static ptr_list_t mem_list;
68 #endif
71 class AddIncludeDir {
72 public:
73 AddIncludeDir(const char *file);
74 ~AddIncludeDir();
76 private:
77 BPath fPath;
81 AddIncludeDir::AddIncludeDir(const char *file)
83 // ignore the special stdin file
84 if (!strcmp(file, "-"))
85 return;
87 if (fPath.SetTo(file) != B_OK
88 || fPath.GetParent(&fPath) != B_OK) {
89 fPath.Unset();
90 return;
93 rdef_add_include_dir(fPath.Path(), false);
97 AddIncludeDir::~AddIncludeDir()
99 if (fPath.InitCheck() == B_OK)
100 rdef_remove_include_dir(fPath.Path());
104 // #pragma mark -
107 void *
108 alloc_mem(size_t size)
110 void *ptr = malloc(size); // can be 0
111 if (ptr == NULL)
112 abort_compile(B_NO_MEMORY, "out of memory");
114 #ifdef DEBUG
115 mem_t mem;
116 mem.ptr = ptr;
117 mem.file = strdup(lexfile);
118 mem.line = yylineno;
119 mem_list.push_front(mem);
120 #else
121 mem_list.push_front(ptr);
122 #endif
124 return ptr;
128 void
129 free_mem(void *ptr)
131 if (ptr != NULL) {
132 #ifdef DEBUG
133 for (mem_iter_t i = mem_list.begin(); i != mem_list.end(); ++i) {
134 if (i->ptr == ptr) {
135 free(i->ptr);
136 free(i->file);
137 mem_list.erase(i);
138 return;
141 #else
142 mem_list.remove(ptr);
143 free(ptr);
144 #endif
149 static void
150 clean_up_mem()
152 #ifdef DEBUG
153 if (mem_list.size() != 0)
154 printf("mem_list leaks %ld objects\n", mem_list.size());
156 for (mem_iter_t i = mem_list.begin(); i != mem_list.end(); ) {
157 printf("%p allocated at %s:%ld\n", i->ptr, i->file, i->line);
158 free(i->ptr);
159 free(i->file);
160 i = mem_list.erase(i);
162 #else
163 free_ptr_list(mem_list);
164 #endif
168 void
169 abort_compile(status_t err, const char *format, ...)
171 va_list ap;
173 rdef_err = err;
174 rdef_err_line = yylineno;
175 strcpy(rdef_err_file, lexfile);
177 va_start(ap, format);
178 vsprintf(rdef_err_msg, format, ap);
179 va_end(ap);
181 abort_compile();
185 void
186 abort_compile()
188 longjmp(abort_jmp, 1);
192 static void
193 compile_file(char *file)
195 strcpy(lexfile, file);
197 // "-" means reading from stdin
198 if (strcmp(file, "-"))
199 yyin = fopen(lexfile, "r");
200 else
201 yyin = stdin;
203 if (yyin == NULL) {
204 strcpy(rdef_err_file, lexfile);
205 rdef_err = RDEF_FILE_NOT_FOUND;
206 return;
209 init_lexer();
210 init_parser();
212 if (setjmp(abort_jmp) == 0) {
213 yyparse();
216 // About error handling: If the bison-generated parser encounters
217 // a syntax error, it calls yyerror(), aborts parsing, and returns
218 // from yyparse(). For other kinds of errors (semantics, problem
219 // writing to BResources, etc), we bail out with a longjmp(). From
220 // then on, we can tell success or failure by looking at rdef_err.
222 clean_up_lexer();
223 clean_up_parser();
224 clean_up_mem();
228 static status_t
229 open_output_file()
231 status_t err = entry.SetTo(rsrc_file, true);
232 if (err == B_OK) {
233 uint32 openMode = B_READ_WRITE | B_CREATE_FILE;
234 bool clobber = false;
236 if (!(flags & RDEF_MERGE_RESOURCES)) {
237 openMode |= B_ERASE_FILE;
238 clobber = true;
241 err = file.SetTo(&entry, openMode);
242 if (err == B_OK)
243 err = rsrc.SetTo(&file, clobber);
246 return err;
250 static void
251 close_output_file()
253 if (rdef_err == B_OK || (flags & RDEF_MERGE_RESOURCES) != 0)
254 rsrc.Sync();
255 else
256 entry.Remove(); // throw away output file
258 file.Unset();
259 entry.Unset();
263 status_t
264 rdef_compile(const char *outputFile)
266 clear_error();
268 if (outputFile == NULL || outputFile[0] == '\0') {
269 rdef_err = B_BAD_VALUE;
270 return rdef_err;
273 rsrc_file = outputFile;
274 rdef_err = open_output_file();
275 if (rdef_err != B_OK)
276 return rdef_err;
278 for (ptr_iter_t i = input_files.begin();
279 (i != input_files.end()) && (rdef_err == B_OK); ++i) {
280 char *path = (char *)*i;
282 AddIncludeDir add(path);
283 compile_file(path);
286 close_output_file();
287 return rdef_err;