/* Pushes a new file into the lexer's input stream while preserving * the existing stream. */ void setup_include(compiler_core_type* compiler, ins_stream_type *arg) { FILE *include_file = 0; char *file_name = 0; char new_include_path_buf[PATH_MAX]; char *new_include_path = 0; char new_file_name[PATH_MAX]; char raw_file_name[PATH_MAX]; size_t length = 0; /* Get the file name for this node */ file_name = arg->head->value.literal; /* Unless the file starts with a / look for it in the current include directory */ if (file_name[0] == '/' || compiler->include_depth < 0) { include_file = fopen(file_name, "r"); } else { /* setup include path */ strcpy(new_include_path_buf, compiler->include_stack[compiler->include_depth]); new_include_path = dirname(new_include_path_buf); /* add 1 for null and 1 for / */ length = strlen(new_include_path) + strlen(file_name) + 2; if (length > PATH_MAX) { (void)fprintf(stderr, "Error %i! Including '%s' - Search path too long: %zi characters\n", errno, file_name, length); parse_error(compiler, compiler->scanner, "Unable to open include file!"); assert(0); } /* Assmeble the new filename */ strcpy(raw_file_name, new_include_path); strcat(raw_file_name, "/"); strcat(raw_file_name, file_name); /* Resolve the path so it makes sense later */ file_name = realpath(raw_file_name, new_file_name); include_file = fopen(file_name, "r"); } if ( !include_file ) { // TODO: Add file name tracking to compiler so we can // report what file include failed in. (void)fprintf(stderr, "Error %i! Including '%s'\n", errno, raw_file_name); parse_error(compiler, compiler->scanner, "Unable to open include file!'"); } else { parse_push_state(compiler, include_file); push_include_path(compiler, file_name); } }
/* Compile a file */ void compile_file(compiler_type *comp_void, char *file_name, bool include_baselib) { compiler_core_type *compiler = (compiler_core_type *)comp_void; ins_stream_type *baselib = 0; /* TODO: should be gc root */ FILE *in = 0; char path[PATH_MAX]; /* Actually parse the input stream. */ yylex_init_extra(compiler, &(compiler->scanner)); in = fopen(file_name, "r"); if (!in) { (void)fprintf(stderr, "Error %i while attempting to open '%s'\n", errno, file_name); assert(0); } //yyset_in(in, compiler->scanner); yy_switch_to_buffer( yy_create_buffer(in, YY_BUF_SIZE, compiler->scanner), compiler->scanner); push_include_path(compiler, file_name); /* TODO: Need a better way to handle GC than leaking */ gc_protect(compiler->gc); /* Inject include for base library */ if (include_baselib) { strcpy(path, compiler->home); strcat(path, "/lib/baselib.scm"); STREAM_NEW(baselib, string, path); setup_include(compiler, baselib); } parse_internal(compiler, compiler->scanner); gc_unprotect(compiler->gc); yylex_destroy(compiler->scanner); }
FILE *rpp::pp::find_include_file(std::string const &p_input_filename, std::string *p_filepath, INCLUDE_POLICY p_include_policy, bool p_skip_current_path) { assert(p_filepath != 0); assert(!p_input_filename.empty()); p_filepath->assign(p_input_filename); if(is_absolute(*p_filepath)) return std::fopen(p_filepath->c_str(), "r"); if(!env.current_file.empty()) _PP_internal::extract_file_path(env.current_file, p_filepath); if(p_include_policy == INCLUDE_LOCAL && !p_skip_current_path) { std::string __tmp(*p_filepath); __tmp += p_input_filename; if(file_exists(__tmp) && !file_isdir(__tmp)) { p_filepath->append(p_input_filename); if((verbose & DEBUGLOG_INCLUDE_DIRECTIVE) != 0) std::cout << "** INCLUDE local " << *p_filepath << ": found" << std::endl; return std::fopen(p_filepath->c_str(), "r"); } } std::vector<std::string>::const_iterator it = include_paths.begin(); if(p_skip_current_path) { it = std::find(include_paths.begin(), include_paths.end(), *p_filepath); if(it != include_paths.end()) { ++it; } else { it = include_paths.begin(); } } for(; it != include_paths.end(); ++it) { if(p_skip_current_path && it == include_paths.begin()) continue; p_filepath->assign(*it); p_filepath->append(p_input_filename); #ifdef Q_OS_MAC /* On MacOSX for those not familiar with the platform, it can group a collection of things * like libraries/header files as installable modules called a framework. A framework has * a well defined layout, so <OpenGL/gl.h> would be transformed into a path * /.../OpenGL.framework/Headers/gl.h */ QString string = QString::fromStdString(p_input_filename); //QStringList list = string.split("/"); //could be used for error checks QString module = string.split("/")[0]; if(!module.contains('.')) { string.replace(module + "/", module + ".framework/Headers/"); string = QString::fromStdString(*it) + string; QFileInfo file = QFileInfo(string); if(file.exists() && file.isFile()) { QString path = QString::fromStdString(*it) + module + ".framework/Headers"; push_include_path(path.toStdString()); if((verbose & DEBUGLOG_INCLUDE_DIRECTIVE) != 0) std::cout << "** INCLUDE system " << string.toStdString() << ": found" << std::endl; return std::fopen(string.toLatin1().data(), "r"); } } #endif if(file_exists(*p_filepath) && !file_isdir(*p_filepath)) { if((verbose & DEBUGLOG_INCLUDE_DIRECTIVE) != 0) std::cout << "** INCLUDE system " << *p_filepath << ": found" << std::endl; return std::fopen(p_filepath->c_str(), "r"); } // Log all search attempts if((verbose & DEBUGLOG_INCLUDE_FULL) != 0) std::cout << "** INCLUDE system " << *p_filepath << ": " << strerror(errno) << std::endl; } return 0; }