// Copyright(C) 1999-2021 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // // See packages/seacas/LICENSE for details #include "apr_symrec.h" #include "aprepro.h" // for symrec, Aprepro, etc #include "aprepro_parser.h" // for Parser, Parser::token, etc #include // for isalnum, isalpha, isupper, etc #include // for errno, EDOM, ERANGE #include // for fetestexcept, FE_DIVBYZERO, etc #include // for math_errhandling, etc #include // for perror #include // for mkstemp #include // for strlen, etc #include // for operator<<, cerr, ostream #include // for allocator, operator+, etc #include // for stat, S_ISDIR #include // for close #include // for vector #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) #include #include #ifndef NOMINMAX #define NOMINMAX #endif #include #if !defined(S_ISDIR) #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) #endif #else #include // for close #endif namespace { std::vector allocations; void copy_string(char *dest, const char *source, long int elements) { char *d; for (d = dest; d + 1 < dest + elements && *source; d++, source++) { *d = *source; } *d = '\0'; } void copy_string(char *dest, const std::string &source, long int elements) { copy_string(dest, source.c_str(), elements); } void new_string_int(const char *from, char **to) { int len = strlen(from); *to = new char[len + 1]; copy_string(*to, from, len + 1); allocations.push_back(*to); } } // namespace namespace SEAMS { extern Aprepro *aprepro; bool arg_check(SEAMS::symrec *symbol, bool is_null) { if (is_null) { std::string err_msg = "Incorrect argument count/type for function '" + symbol->name; err_msg += "'.\n "; err_msg += "The correct syntax is " + symbol->syntax; aprepro->error(err_msg); return false; } return true; } void set_type(const SEAMS::Aprepro &apr, SEAMS::symrec *var, int type) { if (var->name[0] == '_' || !apr.state_is_immutable()) { var->type = type; } else { if (type == Parser::token::VAR) { var->type = Parser::token::IMMVAR; } else if (type == Parser::token::SVAR) { var->type = Parser::token::IMMSVAR; } else { var->type = type; } } } void new_string(const std::string &from, char **to) { new_string_int(from.c_str(), to); } void new_string(const char *from, char **to) { new_string_int(from, to); } void concat_string(const char *from1, const char *from2, char **to) { std::string tmp{from1}; tmp += from2; int len = tmp.length(); *to = new char[len + 1]; copy_string(*to, tmp, len + 1); allocations.push_back(*to); } /* This function returns a pointer to a static character array. * If called multiple times, the name will change on each call, * so don't save the pointer; copy the data it points to if you * need to keep it for awhile. */ const char *get_temp_filename() { static char tmp_name[] = "./aprepro_temp_XXXXXX"; copy_string(tmp_name, "./aprepro_temp_XXXXXX", strlen(tmp_name) + 1); #if defined(__CYGWIN__) && defined(__NO_CYGWIN_OPTION__) int fd = mkstemps(tmp_name, 0); if (fd >= 0) close(fd); #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) copy_string(tmp_name, _mktemp(tmp_name), strlen(tmp_name) + 1); #else int fd = mkstemp(tmp_name); if (fd >= 0) { close(fd); } #endif return tmp_name; } void yyerror(const SEAMS::Aprepro &apr, const std::string &s) { apr.error(s); } void immutable_modify(const SEAMS::Aprepro &apr, const SEAMS::symrec *var) { apr.error("(IMMUTABLE) Variable " + var->name + " is immutable and cannot be modified", true, false); } void undefined_error(const SEAMS::Aprepro &apr, const std::string &var) { if (!apr.inIfdefGetvar) { if (apr.ap_options.require_defined) { apr.error("Undefined variable '" + var + "'"); } else { apr.warning("Undefined variable '" + var + "'"); } } else { apr.inIfdefGetvar = false; } } void redefined_warning(const SEAMS::Aprepro &apr, const SEAMS::symrec *var) { if (var->name[0] != '_' && apr.ap_options.warning_msg) { // See if internal or user-defined variable... std::string type; if (var->isInternal) { type = "Pre"; } else { type = "User"; } apr.warning(type + "-defined Variable '" + var->name + "' redefined"); } } void warning(const SEAMS::Aprepro &apr, const std::string &s) { apr.warning(s); } void math_error(const SEAMS::Aprepro &apr, const char *function) { #if !defined(WIN32) && !defined(__WIN32__) && !defined(_WIN32) && !defined(_MSC_VER) && \ !defined(__MINGW32__) && !defined(_WIN64) && !defined(__MINGW64__) #ifndef math_errhandling #define math_errhandling MATH_ERRNO #endif if (math_errhandling & MATH_ERRNO) { if (errno != 0) { yyerror(apr, function); } if (errno == EDOM) { perror(" DOMAIN error"); } else if (errno == ERANGE) { perror(" RANGE error"); } else if (errno != 0) { perror(" Unknown error"); } errno = 0; } else if (math_errhandling & MATH_ERREXCEPT) { if (std::fetestexcept(FE_INVALID | FE_OVERFLOW | FE_DIVBYZERO) != 0) { yyerror(apr, function); } if (std::fetestexcept(FE_INVALID) != 0) { std::cerr << " DOMAIN error\n"; } else if (std::fetestexcept(FE_OVERFLOW) != 0) { std::cerr << " RANGE error -- overflow\n"; } else if (std::fetestexcept(FE_DIVBYZERO) != 0) { std::cerr << " RANGE error -- divide by zero\n"; } } #endif } void math_error(const char *function) { math_error(*SEAMS::aprepro, function); } /* Convert string to all lower-case and replace all spaces with '_' */ void conv_string(char *string) { char *p = string; while (*p != '\0') { if (*p == ' ') { *p = '_'; } else if (isupper(static_cast(*p)) != 0) { *p = tolower(static_cast(*p)); } p++; } } void cleanup_memory() { for (auto &allocation : allocations) { delete[] allocation; } // Clear the vector to avoid stale pointers. allocations.clear(); } bool is_directory(const std::string &filepath) { struct stat s { }; int ok = stat(filepath.c_str(), &s); if (ok == 0) { return S_ISDIR(s.st_mode); } return false; } bool check_valid_var(const char *var) { /* Check that 'var' meets the restriction for a variable name * L(:|L|D)* * D [0-9] * L [A-Za-z_] */ int length = strlen(var); if (length == 0) { return false; } if ((isalpha(var[0]) == 0) && var[0] != '_') { return false; } for (int i = 1; i < length; i++) { char c = var[i]; if ((isalnum(c) == 0) && c != ':' && c != '_') { return false; } } return true; } } // namespace SEAMS