/* This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data. Copyright (C) 2003-2020 Uwe Schulzweida, See COPYING file for copying and redistribution conditions. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include #include #include "dmemory.h" #include "param_conversion.h" #include "sellist.h" #include "util_wildcards.h" #include "cdo_output.h" // #define SELDEBUG 1 void sellist_init(SelectList &sellist, KVList &kvlist) { sellist.resize(kvlist.size()); int i = 0; for (const auto &kv : kvlist) { auto &e = sellist[i]; e.key = kv.key; e.nvalues = kv.nvalues; e.values.resize(kv.nvalues); for (int k = 0; k < kv.nvalues; ++k) e.values[k] = kv.values[k]; #ifdef SELDEBUG printf("%s =", e.key.c_str()); for (int ii = 0; ii < e.nvalues; ++ii) printf(" '%s'", e.values[ii].c_str()); printf("\n"); #endif ++i; } for (i = 0; i < (int) sellist.size(); ++i) { auto &e = sellist[i]; e.flag = nullptr; e.cvalues = nullptr; #ifdef SELDEBUG printf("%s =", e.key.c_str()); for (int ii = 0; ii < e.nvalues; ++ii) printf(" '%s'", e.values[ii].c_str()); printf("\n"); #endif } } void sellist_destroy(SelectList &sellist) { for (int i = 0; i < (int) sellist.size(); ++i) { auto &e = sellist[i]; if (e.txt) Free(e.txt); if (e.flag) Free(e.flag); if (e.cvalues) Free(e.cvalues); } } void sellist_verify(SelectList &sellist) { for (int i = 0; i < (int) sellist.size(); ++i) { const auto &e = sellist[i]; if (e.type == 0) cdoAbort("Unsupported selection keyword: '%s'!", e.key.c_str()); } } int sellist_add(SelectList &sellist, const char *txt, const char *name, int type) { int idx = -1; for (int i = 0; i < (int) sellist.size(); ++i) { const auto &key = sellist[i].key; if (key == name) { idx = i; break; } } if (idx >= 0 && idx < (int) sellist.size()) { auto &e = sellist[idx]; e.type = type; e.txt = strdup(txt); if (e.nvalues && e.cvalues == nullptr) { switch (type) { case SELLIST_INT: e.cvalues = Malloc(e.nvalues * sizeof(int)); break; case SELLIST_FLT: e.cvalues = Malloc(e.nvalues * sizeof(double)); break; case SELLIST_WORD: e.cvalues = Malloc(e.nvalues * sizeof(char *)); break; } } int j = 0; const auto nvalues = e.nvalues; for (int i = 0; i < nvalues; ++i) switch (type) { case SELLIST_INT: { int first, last, inc; split_intstring(e.values[i].c_str(), first, last, inc); if (first == last) { ((int *) e.cvalues)[j++] = first; } else { int k = 0; if (inc >= 0) for (int ival = first; ival <= last; ival += inc) k++; else for (int ival = first; ival >= last; ival += inc) k++; e.nvalues += k - 1; if (e.nvalues) { e.cvalues = Realloc(e.cvalues, e.nvalues * sizeof(int)); if (inc >= 0) { for (int ival = first; ival <= last; ival += inc) ((int *) e.cvalues)[j++] = ival; } else { for (int ival = first; ival >= last; ival += inc) ((int *) e.cvalues)[j++] = ival; } } } break; } case SELLIST_FLT: ((double *) e.cvalues)[i] = parameter2double(e.values[i].c_str()); break; case SELLIST_WORD: ((const char **) e.cvalues)[i] = parameter2word(e.values[i].c_str()); break; } if (e.nvalues) e.flag = (bool *) Calloc(e.nvalues, sizeof(bool)); #ifdef SELDEBUG printf("%s =", e.key.c_str()); for (int i = 0; i < e.nvalues; ++i) switch (type) { case SELLIST_INT: printf(" %d", ((int *) e.cvalues)[i]); break; case SELLIST_FLT: printf(" %g", ((double *) e.cvalues)[i]); break; case SELLIST_WORD: printf(" %s", ((char **) e.cvalues)[i]); break; } printf("\n"); #endif } return idx; } int sellist_nvalues(const SelectList &sellist, const int idx) { return (idx >= 0 && idx < (int) sellist.size()) ? sellist[idx].nvalues : 0; } void sellist_check_flag(const SelectList &sellist, const int idx) { if (idx < 0 || idx >= (int) sellist.size()) return; const auto nvalues = sellist_nvalues(sellist, idx); if (nvalues) { const auto &e = sellist[idx]; for (int i = 0; i < nvalues; ++i) if (!e.flag[i]) switch (e.type) { case SELLIST_INT: cdoWarning("%s >%d< not found!", e.txt, ((int *) e.cvalues)[i]); break; case SELLIST_FLT: cdoWarning("%s >%g< not found!", e.txt, ((double *) e.cvalues)[i]); break; case SELLIST_WORD: cdoWarning("%s >%s< not found!", e.txt, ((char **) e.cvalues)[i]); break; } } } bool sellist_check(SelectList &sellist, int idx, void *par) { bool found = false; if (idx < 0 || idx >= (int) sellist.size()) return found; const auto nvalues = sellist_nvalues(sellist, idx); if (nvalues) { auto &e = sellist[idx]; for (int i = 0; i < nvalues; ++i) { switch (e.type) { case SELLIST_INT: if (*(int *) par == ((int *) e.cvalues)[i]) { found = true; e.flag[i] = true; } break; case SELLIST_FLT: if (std::fabs(*(double *) par - ((double *) e.cvalues)[i]) < 1.e-4) { found = true; e.flag[i] = true; } break; case SELLIST_WORD: if (wildcardmatch(((char **) e.cvalues)[i], *(char **) par) == 0) { found = true; e.flag[i] = true; } break; } } } return found; } bool sellist_check_date(SelectList &sellist, int idx, const char *par) { bool found = false; if (idx < 0 || idx >= (int) sellist.size()) return found; const auto nvalues = sellist_nvalues(sellist, idx); if (nvalues) { char wcdate[512]; auto &e = sellist[idx]; if (*par == ' ') ++par; for (int i = 0; i < nvalues; ++i) { strcpy(wcdate, e.values[i].c_str()); strcat(wcdate, "*"); if (wildcardmatch(wcdate, par) == 0) { found = true; e.flag[i] = true; } } } return found; } void season_to_months(const char *season, int *imonths); bool sellist_check_season(SelectList &sellist, int idx, int month) { assert(month >= 1 && month <= 12); bool found = false; if (idx < 0 || idx >= (int) sellist.size()) return found; const auto nvalues = sellist_nvalues(sellist, idx); if (nvalues) { int imon[13]; /* 1-12 ! */ const SelectEntry &e = sellist[idx]; for (int i = 0; i < nvalues; ++i) { for (int m = 0; m < 13; ++m) imon[m] = 0; season_to_months(e.values[i].c_str(), imon); if (imon[month]) { found = true; e.flag[i] = true; } } } return found; } void sellist_def_flag(SelectList &sellist, int idx, int vindex, bool flag) { if (idx < 0 || idx >= (int) sellist.size()) return; const auto nvalues = sellist_nvalues(sellist, idx); if (nvalues) { auto &e = sellist[idx]; if (vindex >= 0 && vindex < nvalues) e.flag[vindex] = flag; } } void sellist_get_val(const SelectList &sellist, int idx, int vindex, void *val) { if (idx < 0 || idx >= (int) sellist.size()) return; const auto nvalues = sellist_nvalues(sellist, idx); if (nvalues) { const auto &e = sellist[idx]; if (vindex >= 0 && vindex < nvalues) { switch (e.type) { case SELLIST_INT: *(int *) val = ((int *) e.cvalues)[vindex]; break; case SELLIST_FLT: *(double *) val = ((double *) e.cvalues)[vindex]; break; case SELLIST_WORD: *(const char **) val = ((const char **) e.cvalues)[vindex]; break; } } } } void sellist_def_val(SelectList &sellist, int idx, int vindex, void *val) { if (idx < 0 || idx >= (int) sellist.size()) return; const auto nvalues = sellist_nvalues(sellist, idx); if (nvalues) { auto &e = sellist[idx]; if (vindex >= 0 && vindex < nvalues) { switch (e.type) { case SELLIST_INT: ((int *) e.cvalues)[vindex] = *(int *) val; break; case SELLIST_FLT: ((double *) e.cvalues)[vindex] = *(double *) val; break; case SELLIST_WORD: ((const char **) e.cvalues)[vindex] = *(const char **) val; break; } } } } static void sellist_print_val(const int type, CValues *cvalues, const int i) { switch (type) { case SELLIST_INT: printf(" %d", ((int *) cvalues)[i]); break; case SELLIST_FLT: printf(" %g", ((double *) cvalues)[i]); break; case SELLIST_WORD: printf(" %s", ((char **) cvalues)[i]); break; } } void sellist_print(const SelectList &sellist) { if (sellist.size() > 0) { // printf("Parameter list: %s\n", sellist-> printf("Num Name Type Size Entries\n"); for (int idx = 0; idx < (int) sellist.size(); ++idx) { const auto &e = sellist[idx]; printf("%3d %-16s %4d %4d ", idx + 1, e.key.c_str(), e.type, e.nvalues); auto nvalues = e.nvalues; if (nvalues > 12) nvalues = 11; for (int i = 0; i < nvalues; ++i) sellist_print_val(e.type, (CValues *) e.cvalues, i); if (nvalues < e.nvalues) { printf(" ..."); sellist_print_val(e.type, (CValues *) e.cvalues, e.nvalues - 1); } printf("\n"); } } }