You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1135 lines
26 KiB
1135 lines
26 KiB
2 years ago
|
// Copyright(C) 1999-2023 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_builtin.h"
|
||
|
#include "apr_symrec.h"
|
||
|
|
||
|
#include <cctype>
|
||
|
#include <cerrno>
|
||
|
#include <cfenv>
|
||
|
#include <cmath>
|
||
|
#include <cstdio>
|
||
|
#include <cstdlib>
|
||
|
#include <ctime>
|
||
|
#include <fstream>
|
||
|
#include <stack>
|
||
|
#include <stdexcept>
|
||
|
#include <string>
|
||
|
#include <unordered_map>
|
||
|
#include <utility>
|
||
|
#include <vector>
|
||
|
|
||
|
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \
|
||
|
defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__)
|
||
|
#include <io.h>
|
||
|
#endif
|
||
|
#include "apr_scanner.h"
|
||
|
#include "apr_tokenize.h"
|
||
|
#include "apr_util.h"
|
||
|
#include "aprepro.h"
|
||
|
#include "aprepro_parser.h"
|
||
|
#include <cassert>
|
||
|
#include <cstring>
|
||
|
|
||
|
#include <random>
|
||
|
|
||
|
#ifndef PI
|
||
|
#define PI 3.141592653589793238462643
|
||
|
#endif
|
||
|
|
||
|
namespace {
|
||
|
std::unordered_map<size_t, std::vector<std::string>> tokenized_strings;
|
||
|
|
||
|
std::vector<std::string> &get_tokenized_strings(const char *string, const char *delm)
|
||
|
{
|
||
|
// key is address of string + hash of delimiter
|
||
|
size_t key = std::hash<std::string>{}(string) + std::hash<std::string>{}(delm);
|
||
|
if (tokenized_strings.find(key) == tokenized_strings.end()) {
|
||
|
std::string temp = string;
|
||
|
auto tokens = SEAMS::tokenize(temp, delm);
|
||
|
tokenized_strings[key] = std::move(tokens);
|
||
|
}
|
||
|
return tokenized_strings[key];
|
||
|
}
|
||
|
|
||
|
std::random_device rd;
|
||
|
std::mt19937_64 rng(rd());
|
||
|
|
||
|
void reset_error()
|
||
|
{
|
||
|
#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_ERREXCEPT) {
|
||
|
std::feclearexcept(FE_ALL_EXCEPT);
|
||
|
}
|
||
|
if (math_errhandling & MATH_ERRNO) {
|
||
|
errno = 0;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
} // namespace
|
||
|
|
||
|
namespace SEAMS {
|
||
|
|
||
|
extern SEAMS::Aprepro *aprepro;
|
||
|
|
||
|
#define d2r(x) ((x)*PI / 180.)
|
||
|
#define r2d(x) ((x)*180. / PI)
|
||
|
|
||
|
#ifndef max
|
||
|
#define max(x, y) (x) > (y) ? (x) : (y)
|
||
|
#define min(x, y) (x) < (y) ? (x) : (y)
|
||
|
#endif
|
||
|
|
||
|
double do_time()
|
||
|
{
|
||
|
time_t timer = time(nullptr);
|
||
|
return timer;
|
||
|
}
|
||
|
|
||
|
double do_FtoC(double F) { return (F - 32.0) / 1.8; }
|
||
|
|
||
|
double do_CtoF(double C) { return (C * 1.8) + 32.0; }
|
||
|
|
||
|
// DO_INT: Calculate integer nearest to zero from value
|
||
|
double do_int(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = (x < 0 ? -std::floor(-(x)) : std::floor(x));
|
||
|
SEAMS::math_error("int");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
// DO_NINT: Calculate integer nearest value
|
||
|
double do_nint(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = (x < 0 ? -std::floor(0.5 - x) : std::floor(x + 0.5));
|
||
|
SEAMS::math_error("nint");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
// DO_DIST: Calculate distance between point 1 at (x1,y1) and
|
||
|
// point 2 at (x2,y2).
|
||
|
|
||
|
double do_dist(double x1, double y1, double x2, double y2)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = std::hypot((x1 - x2), (y1 - y2));
|
||
|
SEAMS::math_error("hypot");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
// DO_ANGLE: Calculate angle (radians) between vector 1 at (0,0; x1,y1) and
|
||
|
// vector 2 at (0,0; x2,y2).
|
||
|
|
||
|
double do_angle(double x1, double y1, double x2, double y2)
|
||
|
{
|
||
|
double temp = ((x1 * x2) + (y1 * y2)) / (std::hypot(x1, y1) * std::hypot(x2, y2));
|
||
|
reset_error();
|
||
|
temp = acos(temp);
|
||
|
SEAMS::math_error("angle");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
// DO_ANGLE: Calculate angle (degrees) between vector 1 at (0,0; x1,y1) and
|
||
|
// vector 2 at (0,0; x2,y2).
|
||
|
|
||
|
double do_angled(double x1, double y1, double x2, double y2)
|
||
|
{
|
||
|
double temp = ((x1 * x2) + (y1 * y2)) / (std::hypot(x1, y1) * std::hypot(x2, y2));
|
||
|
reset_error();
|
||
|
temp = r2d(acos(temp));
|
||
|
SEAMS::math_error("angled");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
// DO_HYPOT: calculate sqrt(p^2 + q^2)
|
||
|
double do_hypot(double x, double y) { return std::hypot(x, y); }
|
||
|
|
||
|
double do_pow(double x, double y)
|
||
|
{
|
||
|
// X^Y
|
||
|
return std::pow(x, y);
|
||
|
}
|
||
|
|
||
|
double do_max(double x, double y)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = max(x, y);
|
||
|
SEAMS::math_error("max");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_min(double x, double y)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = min(x, y);
|
||
|
SEAMS::math_error("min");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_d2r(double x) { return (d2r(x)); }
|
||
|
|
||
|
double do_r2d(double x) { return (r2d(x)); }
|
||
|
|
||
|
double do_sind(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = sin(d2r(x));
|
||
|
SEAMS::math_error("sind");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_sin(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = sin(x);
|
||
|
SEAMS::math_error("sin");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_cosd(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = cos(d2r(x));
|
||
|
SEAMS::math_error("cosd");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_cos(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = cos(x);
|
||
|
SEAMS::math_error("cos");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_tand(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = tan(d2r(x));
|
||
|
SEAMS::math_error("tand");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_tan(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = tan(x);
|
||
|
SEAMS::math_error("tan");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_atan2d(double x, double y)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = r2d(atan2(x, y));
|
||
|
SEAMS::math_error("atan2d");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_atan2(double x, double y)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = atan2(x, y);
|
||
|
SEAMS::math_error("atan2");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_atand(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = r2d(atan(x));
|
||
|
SEAMS::math_error("atand");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_atan(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = atan(x);
|
||
|
SEAMS::math_error("atan");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_asind(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = r2d(asin(x));
|
||
|
SEAMS::math_error("asind");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_asin(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = asin(x);
|
||
|
SEAMS::math_error("asin");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_acosd(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = r2d(acos(x));
|
||
|
SEAMS::math_error("acosd");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_acos(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = acos(x);
|
||
|
SEAMS::math_error("acos");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
// do_srand(x) Seed the random generator with the specified integer value
|
||
|
double do_srand(double seed)
|
||
|
{
|
||
|
rng.seed(static_cast<size_t>(seed));
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
// do_rand(x) returns a random double in the range 0<= do_rand <= x
|
||
|
double do_rand(double xl, double xh)
|
||
|
{
|
||
|
std::uniform_real_distribution<double> dist(xl, xh);
|
||
|
return dist(rng);
|
||
|
}
|
||
|
|
||
|
double do_rand_normal(double mean, double stddev)
|
||
|
{
|
||
|
std::normal_distribution<> dist(mean, stddev);
|
||
|
return dist(rng);
|
||
|
}
|
||
|
|
||
|
double do_rand_lognormal(double mean, double stddev)
|
||
|
{
|
||
|
std::lognormal_distribution<> dist(mean, stddev);
|
||
|
return dist(rng);
|
||
|
}
|
||
|
|
||
|
double do_rand_weibull(double alpha, double beta)
|
||
|
{
|
||
|
std::weibull_distribution<> dist(alpha, beta);
|
||
|
return dist(rng);
|
||
|
}
|
||
|
|
||
|
double do_sign(double x, double y)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = (y) >= 0 ? fabs(x) : -fabs(x);
|
||
|
SEAMS::math_error("sign");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_dim(double x, double y)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = x - (min(x, y));
|
||
|
SEAMS::math_error("dim");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_fabs(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = fabs(x);
|
||
|
SEAMS::math_error("fabs");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_ceil(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = ceil(x);
|
||
|
SEAMS::math_error("ceil");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_cosh(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = cosh(x);
|
||
|
SEAMS::math_error("cosh");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_exp(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = exp(x);
|
||
|
SEAMS::math_error("exp");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_expm1(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = std::expm1(x);
|
||
|
SEAMS::math_error("exp");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_erf(double x) { return std::erf(x); }
|
||
|
|
||
|
double do_erfc(double x) { return std::erfc(x); }
|
||
|
|
||
|
double do_floor(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = floor(x);
|
||
|
SEAMS::math_error("floor");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_fmod(double x, double y)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = fmod(x, y);
|
||
|
SEAMS::math_error("fmod");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_log(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = std::log(x);
|
||
|
SEAMS::math_error("log");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_log10(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = std::log10(x);
|
||
|
SEAMS::math_error("log10");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_sinh(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = sinh(x);
|
||
|
SEAMS::math_error("sinh");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_sqrt(double x)
|
||
|
{
|
||
|
feclearexcept(FE_ALL_EXCEPT);
|
||
|
reset_error();
|
||
|
double temp = std::sqrt(x);
|
||
|
if (fetestexcept(FE_INVALID | FE_OVERFLOW | FE_DIVBYZERO) != 0) {
|
||
|
SEAMS::math_error("sqrt");
|
||
|
}
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_cbrt(double x)
|
||
|
{
|
||
|
feclearexcept(FE_ALL_EXCEPT);
|
||
|
reset_error();
|
||
|
double temp = std::cbrt(x);
|
||
|
if (fetestexcept(FE_INVALID | FE_OVERFLOW | FE_DIVBYZERO) != 0) {
|
||
|
SEAMS::math_error("sqrt");
|
||
|
}
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_tanh(double x)
|
||
|
{
|
||
|
reset_error();
|
||
|
double temp = tanh(x);
|
||
|
SEAMS::math_error("tanh");
|
||
|
return (temp);
|
||
|
}
|
||
|
|
||
|
double do_polarX(double rad, double ang) { return (rad * cos(d2r(ang))); }
|
||
|
|
||
|
double do_polarY(double rad, double ang) { return (rad * sin(d2r(ang))); }
|
||
|
|
||
|
double do_lgamma(double val) { return std::lgamma(val); }
|
||
|
|
||
|
double do_tgamma(double val) { return std::tgamma(val); }
|
||
|
|
||
|
double do_juldayhms(double mon, double day, double year, double h, double mi, double se)
|
||
|
{
|
||
|
double seconds = h * 3600.0 + mi * 60 + se;
|
||
|
|
||
|
long m = static_cast<long>(mon);
|
||
|
long d = static_cast<long>(day);
|
||
|
long y = static_cast<long>(year);
|
||
|
|
||
|
if (m > 2) {
|
||
|
m -= 3;
|
||
|
}
|
||
|
else {
|
||
|
m += 9;
|
||
|
--y;
|
||
|
}
|
||
|
long c = y / 100L;
|
||
|
long ya = y - (100L * c);
|
||
|
long j = (146097L * c) / 4L + (1461L * ya) / 4L + (153L * m + 2L) / 5L + d + 1721119L;
|
||
|
if (seconds < 12 * 3600.0) {
|
||
|
j--;
|
||
|
seconds += 12.0 * 3600.0;
|
||
|
}
|
||
|
else {
|
||
|
seconds = seconds - 12.0 * 3600.0;
|
||
|
}
|
||
|
return (j + (seconds / 3600.0) / 24.0);
|
||
|
}
|
||
|
|
||
|
double do_julday(double mon, double day, double year)
|
||
|
{
|
||
|
return do_juldayhms(mon, day, year, 0.0, 0.0, 0.0);
|
||
|
}
|
||
|
|
||
|
double do_log1p(double x) { return std::log1p(x); }
|
||
|
|
||
|
double do_acosh(double x) { return std::acosh(x); }
|
||
|
|
||
|
double do_asinh(double x) { return std::asinh(x); }
|
||
|
|
||
|
double do_atanh(double x) { return std::atanh(x); }
|
||
|
|
||
|
double do_rows(const array *arr) { return arr->rows; }
|
||
|
|
||
|
double do_cols(const array *arr) { return arr->cols; }
|
||
|
|
||
|
// --------------------------STRING FUNCTIONS------------------------
|
||
|
const char *do_version()
|
||
|
{
|
||
|
char *tmp;
|
||
|
new_string(SEAMS::Aprepro::version().c_str(), &tmp);
|
||
|
return tmp;
|
||
|
}
|
||
|
|
||
|
const char *do_get_date()
|
||
|
{
|
||
|
char *tmp;
|
||
|
const size_t bufsize = 32;
|
||
|
static char tmpstr[32];
|
||
|
|
||
|
time_t timer = time(nullptr);
|
||
|
struct tm *timeptr = localtime(&timer);
|
||
|
|
||
|
// First the date in the form CCYY/MM/DD
|
||
|
strftime(tmpstr, bufsize, "%Y/%m/%d", timeptr);
|
||
|
new_string(tmpstr, &tmp);
|
||
|
return (tmp);
|
||
|
}
|
||
|
|
||
|
const char *do_get_iso_date()
|
||
|
{
|
||
|
char *tmp;
|
||
|
const size_t bufsize = 32;
|
||
|
static char tmpstr[32];
|
||
|
|
||
|
time_t timer = time(nullptr);
|
||
|
struct tm *timeptr = localtime(&timer);
|
||
|
|
||
|
// First the date in the form CCYY/MM/DD
|
||
|
strftime(tmpstr, bufsize, "%Y%m%d", timeptr);
|
||
|
new_string(tmpstr, &tmp);
|
||
|
return (tmp);
|
||
|
}
|
||
|
|
||
|
const char *do_get_time()
|
||
|
{
|
||
|
char *tmp;
|
||
|
const size_t bufsize = 32;
|
||
|
static char tmpstr[32];
|
||
|
|
||
|
time_t timer = time(nullptr);
|
||
|
struct tm *timeptr = localtime(&timer);
|
||
|
|
||
|
// Now the time in the form HH:MM:SS where 0 <= HH < 24
|
||
|
strftime(tmpstr, bufsize, "%H:%M:%S", timeptr);
|
||
|
new_string(tmpstr, &tmp);
|
||
|
return (tmp);
|
||
|
}
|
||
|
|
||
|
const char *do_tolower(char *string)
|
||
|
{
|
||
|
char *p = string;
|
||
|
while (*p != '\0') {
|
||
|
if (isupper(static_cast<int>(*p)) != 0) {
|
||
|
*p = tolower(static_cast<int>(*p));
|
||
|
}
|
||
|
p++;
|
||
|
}
|
||
|
return (string);
|
||
|
}
|
||
|
|
||
|
const char *do_toupper(char *string)
|
||
|
{
|
||
|
char *p = string;
|
||
|
while (*p != '\0') {
|
||
|
if (islower(static_cast<int>(*p)) != 0) {
|
||
|
*p = toupper(static_cast<int>(*p));
|
||
|
}
|
||
|
p++;
|
||
|
}
|
||
|
return (string);
|
||
|
}
|
||
|
|
||
|
const char *do_tostring(double x)
|
||
|
{
|
||
|
char *tmp;
|
||
|
static char tmpstr[128];
|
||
|
if (x == 0.0) {
|
||
|
new_string("0", &tmp);
|
||
|
return (tmp);
|
||
|
}
|
||
|
|
||
|
SEAMS::symrec *format;
|
||
|
format = aprepro->getsym("_FORMAT");
|
||
|
snprintf(tmpstr, 128, format->value.svar.c_str(), x);
|
||
|
new_string(tmpstr, &tmp);
|
||
|
return (tmp);
|
||
|
}
|
||
|
|
||
|
const char *do_output(char *filename)
|
||
|
{
|
||
|
aprepro->outputStream.top()->flush();
|
||
|
|
||
|
if (std::strcmp(filename, "pop") == 0 || std::strcmp(filename, "stdout") == 0) {
|
||
|
while (aprepro->outputStream.size() > 1) {
|
||
|
std::ostream *output = aprepro->outputStream.top();
|
||
|
aprepro->outputStream.pop();
|
||
|
delete output;
|
||
|
}
|
||
|
|
||
|
aprepro->info("Output now redirected to original output stream.\n");
|
||
|
}
|
||
|
else {
|
||
|
std::ostream *output = new std::ofstream(filename);
|
||
|
aprepro->outputStream.push(output);
|
||
|
aprepro->info("Output now redirected to file'" + std::string(filename) + "'.\n");
|
||
|
}
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_append(char *filename)
|
||
|
{
|
||
|
aprepro->outputStream.top()->flush();
|
||
|
|
||
|
if (std::strcmp(filename, "pop") == 0 || std::strcmp(filename, "stdout") == 0) {
|
||
|
while (aprepro->outputStream.size() > 1) {
|
||
|
std::ostream *output = aprepro->outputStream.top();
|
||
|
aprepro->outputStream.pop();
|
||
|
delete output;
|
||
|
}
|
||
|
|
||
|
aprepro->info("Output now redirected to original output stream.\n");
|
||
|
}
|
||
|
else {
|
||
|
auto output = new std::ofstream(filename, std::ios_base::app); // Append
|
||
|
aprepro->outputStream.push(output);
|
||
|
|
||
|
aprepro->info("Output now redirected to file '" + std::string(filename) + "'\n");
|
||
|
}
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
double do_word_count(char *string, char *delm)
|
||
|
{
|
||
|
return static_cast<double>(get_tokenized_strings(string, delm).size());
|
||
|
}
|
||
|
|
||
|
double do_find_word(char *word, char *string, char *delm)
|
||
|
{
|
||
|
const auto &tokens = get_tokenized_strings(string, delm);
|
||
|
std::string sword{word};
|
||
|
for (size_t i = 0; i < tokens.size(); i++) {
|
||
|
if (tokens[i] == sword) {
|
||
|
return i + 1;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const char *do_get_word(double n, char *string, char *delm)
|
||
|
{
|
||
|
auto &tokens = get_tokenized_strings(string, delm);
|
||
|
|
||
|
size_t in = static_cast<size_t>(n);
|
||
|
if (tokens.size() >= in) {
|
||
|
char *word = nullptr;
|
||
|
new_string(tokens[in - 1], &word);
|
||
|
return word;
|
||
|
}
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
const char *do_file_to_string(char *filename)
|
||
|
{
|
||
|
char *ret_string = nullptr;
|
||
|
std::fstream *file = aprepro->open_file(filename, "r");
|
||
|
|
||
|
if (file != nullptr) {
|
||
|
std::ostringstream lines;
|
||
|
std::string line;
|
||
|
while (std::getline(*file, line)) {
|
||
|
lines << line << '\n';
|
||
|
}
|
||
|
|
||
|
new_string(lines.str(), &ret_string);
|
||
|
}
|
||
|
return ret_string;
|
||
|
}
|
||
|
|
||
|
const char *do_getenv(char *env)
|
||
|
{
|
||
|
if (env == nullptr) {
|
||
|
return "";
|
||
|
}
|
||
|
char *tmp = getenv(env);
|
||
|
if (tmp != nullptr) {
|
||
|
char *ret_string;
|
||
|
new_string(tmp, &ret_string);
|
||
|
return (ret_string);
|
||
|
}
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
double do_strtod(char *string)
|
||
|
{
|
||
|
reset_error();
|
||
|
double x = strtod(string, nullptr);
|
||
|
SEAMS::math_error("strtod");
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
const char *do_dumpsym()
|
||
|
{
|
||
|
aprepro->dumpsym(SEAMS::Parser::token::VAR, false);
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_dumpsym_json()
|
||
|
{
|
||
|
aprepro->dumpsym_json();
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_dumpfunc()
|
||
|
{
|
||
|
aprepro->dumpsym(SEAMS::Parser::token::FNCT, true);
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_dumpvar()
|
||
|
{
|
||
|
aprepro->dumpsym(SEAMS::Parser::token::VAR, true);
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_dumpsym1(char *pre)
|
||
|
{
|
||
|
aprepro->dumpsym(SEAMS::Parser::token::VAR, pre, false);
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_dumpfunc1(char *pre)
|
||
|
{
|
||
|
aprepro->dumpsym(SEAMS::Parser::token::FNCT, pre, true);
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_dumpvar1(char *pre)
|
||
|
{
|
||
|
aprepro->dumpsym(SEAMS::Parser::token::VAR, pre, true);
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
double do_option(char *option, double value)
|
||
|
{
|
||
|
double current = -1;
|
||
|
|
||
|
if (std::strcmp(option, "warning") == 0) {
|
||
|
current = static_cast<double>(aprepro->ap_options.warning_msg);
|
||
|
aprepro->ap_options.warning_msg = value != 0.0;
|
||
|
}
|
||
|
|
||
|
else if (std::strcmp(option, "info") == 0) {
|
||
|
current = static_cast<double>(aprepro->ap_options.info_msg);
|
||
|
aprepro->ap_options.info_msg = value != 0.0;
|
||
|
}
|
||
|
|
||
|
else if (std::strcmp(option, "debugging") == 0) {
|
||
|
current = static_cast<double>(aprepro->ap_options.debugging);
|
||
|
aprepro->ap_options.debugging = value != 0.0;
|
||
|
}
|
||
|
|
||
|
else if (std::strcmp(option, "statistics") == 0) {
|
||
|
aprepro->statistics();
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
aprepro->error(
|
||
|
"Valid arguments to option are: 'warning', 'info', 'debugging', and 'statistics'\n",
|
||
|
false);
|
||
|
}
|
||
|
return current;
|
||
|
}
|
||
|
|
||
|
const char *do_include_path(char *new_path)
|
||
|
{
|
||
|
aprepro->ap_options.include_path = new_path;
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_intout(double intval)
|
||
|
{
|
||
|
// convert 'intval' to a string using an integer format
|
||
|
// This can be used if you need to set the default output
|
||
|
// format to force the decimal point. In that case, integers
|
||
|
// also have a decimal point which is usually not wanted.
|
||
|
// Using 'intout(val)', val will be converted to a string
|
||
|
// using an integer format
|
||
|
|
||
|
char *tmp;
|
||
|
if (intval == 0.0) {
|
||
|
new_string("0", &tmp);
|
||
|
return (tmp);
|
||
|
}
|
||
|
|
||
|
std::string tmpstr = std::to_string(static_cast<int>(intval));
|
||
|
new_string(tmpstr.c_str(), &tmp);
|
||
|
return (tmp);
|
||
|
}
|
||
|
|
||
|
const char *do_execute(char *string)
|
||
|
{
|
||
|
aprepro->lexer->execute(string);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_rescan(char *string)
|
||
|
{
|
||
|
aprepro->lexer->rescan(string);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_import(char *string)
|
||
|
{
|
||
|
aprepro->lexer->import_handler(string);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_if(double x)
|
||
|
{
|
||
|
aprepro->inIfdefGetvar = false;
|
||
|
aprepro->lexer->if_handler(x);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_notif(double x)
|
||
|
{
|
||
|
aprepro->lexer->if_handler(!x);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_elseif(double x)
|
||
|
{
|
||
|
aprepro->lexer->elseif_handler(x);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_str_if(char *string)
|
||
|
{
|
||
|
std::string test(string);
|
||
|
aprepro->lexer->if_handler(static_cast<double>(!test.empty()));
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_str_notif(char *string)
|
||
|
{
|
||
|
std::string test(string);
|
||
|
aprepro->lexer->if_handler(static_cast<double>(test.empty()));
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_str_elseif(char *string)
|
||
|
{
|
||
|
std::string test(string);
|
||
|
aprepro->lexer->elseif_handler(static_cast<double>(!test.empty()));
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_switch(double x)
|
||
|
{
|
||
|
aprepro->lexer->switch_handler(x);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_case(double x)
|
||
|
{
|
||
|
aprepro->lexer->case_handler(x);
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
const char *do_extract(char *string, char *begin, char *end)
|
||
|
{
|
||
|
// From 'string' return a substring delimited by 'begin' and 'end'.
|
||
|
// 'begin' is included in the string, but 'end' is not. If
|
||
|
// 'begin' does not appear in the string, return nullptr; If 'end'
|
||
|
// does not appear, then return the remainder of the string. If
|
||
|
// 'begin' == "", then start at beginning; if 'end' == "", then
|
||
|
// return remainder of the string.
|
||
|
char *start = string;
|
||
|
|
||
|
if (std::strlen(begin) > 0) {
|
||
|
start = std::strstr(string, begin);
|
||
|
if (start == nullptr) {
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int len = std::strlen(start);
|
||
|
if (std::strlen(end) > 0) {
|
||
|
char *finish = std::strstr(start, end);
|
||
|
if (finish != nullptr) {
|
||
|
len = finish - start;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::string tmpstr(start, 0, len);
|
||
|
char *tmp;
|
||
|
new_string(tmpstr, &tmp);
|
||
|
return tmp;
|
||
|
}
|
||
|
|
||
|
const char *do_get_temp_filename()
|
||
|
{
|
||
|
char *filename;
|
||
|
new_string(get_temp_filename(), &filename);
|
||
|
return filename;
|
||
|
}
|
||
|
|
||
|
const char *do_error(char *error_string)
|
||
|
{
|
||
|
// Print error message (to stderr) and exit
|
||
|
yyerror(*aprepro, error_string);
|
||
|
throw std::runtime_error(std::string(error_string));
|
||
|
// NOTREACHED
|
||
|
return (nullptr);
|
||
|
}
|
||
|
|
||
|
const char *do_print_array(const array *my_array_data)
|
||
|
{
|
||
|
if (my_array_data != nullptr) {
|
||
|
std::ostringstream lines;
|
||
|
|
||
|
int rows = my_array_data->rows;
|
||
|
int cols = my_array_data->cols;
|
||
|
|
||
|
int idx = 0;
|
||
|
|
||
|
for (int ir = 0; ir < rows; ir++) {
|
||
|
if (ir > 0) {
|
||
|
lines << "\n";
|
||
|
}
|
||
|
lines << "\t";
|
||
|
for (int ic = 0; ic < cols; ic++) {
|
||
|
lines << my_array_data->data[idx++];
|
||
|
if (ic < cols - 1) {
|
||
|
lines << "\t";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
char *ret_string;
|
||
|
new_string(lines.str(), &ret_string);
|
||
|
return ret_string;
|
||
|
}
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
const char *do_delete(char *string)
|
||
|
{
|
||
|
aprepro->remove_variable(string);
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
array *do_make_array(double rows, double cols)
|
||
|
{
|
||
|
auto array_data = aprepro->make_array(rows, cols);
|
||
|
return array_data;
|
||
|
}
|
||
|
|
||
|
array *do_make_array_init(double rows, double cols, double init)
|
||
|
{
|
||
|
auto array_data = aprepro->make_array(rows, cols);
|
||
|
int isize = (int)rows * int(cols);
|
||
|
for (int i = 0; i < isize; i++) {
|
||
|
array_data->data[i] = init;
|
||
|
}
|
||
|
return array_data;
|
||
|
}
|
||
|
|
||
|
array *do_identity(double size)
|
||
|
{
|
||
|
auto array_data = aprepro->make_array(size, size);
|
||
|
|
||
|
int isize = size;
|
||
|
for (int i = 0; i < isize; i++) {
|
||
|
array_data->data[i * isize + i] = 1.0;
|
||
|
}
|
||
|
return array_data;
|
||
|
}
|
||
|
|
||
|
array *do_linear_array(double init, double final, double count)
|
||
|
{
|
||
|
// Create 1D array with `count` rows and 1 column.
|
||
|
// Values are linearly spaced from `init` to `final`
|
||
|
int isize = count;
|
||
|
auto array_data = aprepro->make_array(count, 1);
|
||
|
|
||
|
double inc = (final - init) / (count - 1);
|
||
|
for (int i = 0; i < isize; i++) {
|
||
|
array_data->data[i] = init + (double)i * inc;
|
||
|
}
|
||
|
return array_data;
|
||
|
}
|
||
|
|
||
|
array *do_transpose(const array *a)
|
||
|
{
|
||
|
auto array_data = aprepro->make_array(a->cols, a->rows);
|
||
|
|
||
|
for (int i = 0; i < a->rows; i++) {
|
||
|
for (int j = 0; j < a->cols; j++) {
|
||
|
array_data->data[j * a->rows + i] = a->data[i * a->cols + j];
|
||
|
}
|
||
|
}
|
||
|
return array_data;
|
||
|
}
|
||
|
|
||
|
array *do_csv_array1(const char *filename) { return do_csv_array(filename, 0.0); }
|
||
|
|
||
|
array *do_csv_array(const char *filename, double skip)
|
||
|
{
|
||
|
size_t rows_to_skip = static_cast<size_t>(skip);
|
||
|
|
||
|
std::fstream *file = aprepro->open_file(filename, "r");
|
||
|
if (file != nullptr) {
|
||
|
|
||
|
size_t rows = 0;
|
||
|
size_t cols = 0;
|
||
|
|
||
|
const char *delim = ",\t ";
|
||
|
std::string line;
|
||
|
while (std::getline(*file, line)) {
|
||
|
rows++;
|
||
|
if (rows > rows_to_skip) {
|
||
|
auto tokens = tokenize(line, delim);
|
||
|
cols = tokens.size() > cols ? tokens.size() : cols;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
auto array_data = aprepro->make_array(rows - rows_to_skip, cols);
|
||
|
|
||
|
// Read file again storing entries in array_data->data
|
||
|
file->clear();
|
||
|
file->seekg(0);
|
||
|
|
||
|
int idx = 0;
|
||
|
rows = 0;
|
||
|
while (std::getline(*file, line)) {
|
||
|
if (++rows > rows_to_skip) {
|
||
|
auto tokens = tokenize(line, delim);
|
||
|
for (size_t i = 0; i < static_cast<size_t>(array_data->cols); i++) {
|
||
|
if (i < tokens.size()) {
|
||
|
array_data->data[idx++] = std::stod(tokens[i]);
|
||
|
}
|
||
|
else {
|
||
|
array_data->data[idx++] = 0.0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
assert(rows - rows_to_skip == (size_t)array_data->rows);
|
||
|
delete file;
|
||
|
return array_data;
|
||
|
}
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
array *do_csv_array2(const char *filename, const char *comment)
|
||
|
{
|
||
|
std::fstream *file = aprepro->open_file(filename, "r");
|
||
|
if (file != nullptr) {
|
||
|
|
||
|
size_t rows = 0;
|
||
|
size_t cols = 0;
|
||
|
const char *delim = ",\t ";
|
||
|
|
||
|
std::string line;
|
||
|
while (std::getline(*file, line)) {
|
||
|
if (line[0] != comment[0]) {
|
||
|
rows++;
|
||
|
auto tokens = tokenize(line, delim);
|
||
|
cols = tokens.size() > cols ? tokens.size() : cols;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
auto array_data = aprepro->make_array(rows, cols);
|
||
|
|
||
|
// Read file again storing entries in array_data->data
|
||
|
file->clear();
|
||
|
file->seekg(0);
|
||
|
|
||
|
int idx = 0;
|
||
|
rows = 0;
|
||
|
while (std::getline(*file, line)) {
|
||
|
if (line[0] != comment[0]) {
|
||
|
rows++;
|
||
|
auto tokens = tokenize(line, delim);
|
||
|
for (size_t i = 0; i < static_cast<size_t>(array_data->cols); i++) {
|
||
|
if (i < tokens.size()) {
|
||
|
array_data->data[idx++] = std::stod(tokens[i]);
|
||
|
}
|
||
|
else {
|
||
|
array_data->data[idx++] = 0.0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
assert((int)rows == array_data->rows);
|
||
|
delete file;
|
||
|
return array_data;
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
array *do_array_from_string(const char *string, const char *delm)
|
||
|
{
|
||
|
auto tokens = SEAMS::tokenize(string, delm);
|
||
|
auto array_data = aprepro->make_array(tokens.size(), 1);
|
||
|
|
||
|
int idx = 0;
|
||
|
for (const auto &token : tokens) {
|
||
|
array_data->data[idx++] = std::stod(token);
|
||
|
}
|
||
|
assert(idx == array_data->rows);
|
||
|
return array_data;
|
||
|
}
|
||
|
} // namespace SEAMS
|