From 98daf03d6f2a8b0b345866f4ab2b5c7edab1a67b Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Sat, 30 Mar 2024 12:05:05 +0100
Subject: [PATCH 01/13] avoiding memory leaks on errors in weekly schedule for
#1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 283 ++++++++++++++-------
IBPSA/Resources/C-Sources/WeeklySchedule.h | 12 +-
2 files changed, 204 insertions(+), 91 deletions(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index a01217d8f4..14d5b35ee3 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -30,12 +30,10 @@ int cmpfun(const void * tuple1, const void * tuple2) {
}
void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t_offset, char* stringData) {
- FILE* fp;
const int bufLen = 255;
WeeklySchedule* scheduleID = NULL;
- char* token = NULL;
- struct TimeDataTuple **rules;
+
int i = 0; /* iterator */
int j = 0; /* iterator */
int k = 0; /* iterator */
@@ -48,34 +46,50 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
int comment = 0; /* we are parsing a comment */
int n_rulesInMem = 0; /* number of rules for which we have allocated memory */
int n_rulesInRow = 0; /* number of rules that exist in the current row */
- int n_rowsUnpacked = 0; /* total number of unpacked rules */
int n_rowsPacked = 0; /* number of rules */
int n_newLines = 0; /* number of newlines */
char c; /* the character that is being parsed in this iteration */
int parseToken = 0;
double timeStamp;
- char* buff2;
int tokenLen;
int offset = 0;
- double* lastData = NULL;
-
scheduleID = (WeeklySchedule*)calloc(1, sizeof(WeeklySchedule));
- if ( scheduleID == NULL)
+ if ( scheduleID == NULL){
ModelicaFormatError("Failed to allocate memory for scheduleID in WeeklySchedule.c.");
+ }
- token = (char*)calloc(sizeof(char), bufLen);
- if ( token == NULL)
- ModelicaFormatError("Failed to allocate memory for token in WeeklySchedule.c.");
+ scheduleID->n_allocatedRules = 0;
+ scheduleID->n_allocatedRulesData = 0;
+ scheduleID->lastData = NULL;
+ scheduleID->token = NULL;
+ scheduleID->fp = NULL;
+ scheduleID->buff2 = NULL;
+ scheduleID->rules = NULL;
+
+ scheduleID->token = (char*)calloc(sizeof(char), bufLen);
+ if ( scheduleID->token == NULL){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Failed to allocate memory for token in WeeklySchedule.c.");
+ }
if (tableOnFile){
- fp = fopen(name, "r");
- if (fp == NULL) {
+ scheduleID->fp = fopen(name, "r");
+ if (scheduleID->fp == NULL) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to open weekly schedule '%s'.", name);
}
}
+ scheduleID->buff2 = (char*)calloc(sizeof(char), bufLen);
+ if (scheduleID->buff2 == NULL){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Failed to allocate memory for buff in WeeklySchedule.c.");
+ }
/* Identify 'tokens' by splitting on (one or more) whitespace characters. */
/* Each token is parsed and special behaviour is created for comments and the header. */
@@ -87,7 +101,7 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
parseToken = 0;
if (tableOnFile){
- c = fgetc( fp ); /* read a character from the file */
+ c = fgetc( scheduleID->fp ); /* read a character from the file */
}else{
c = stringData[j]; /* read a character from the string */
j++;
@@ -95,13 +109,17 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
if ( c == EOF || c == '\0') {
if (!tableOnFile && c == '\0'){
break;
- }else if (tableOnFile && feof(fp)) {
+ }else if (tableOnFile && feof(scheduleID->fp)) {
break; /* exit the while loop */
} else {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Error while reading file '%s'.", name);
}
}{
if (index >= bufLen - 2) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Buffer overflow when reading weekly schedule '%s'.", name);
}
@@ -115,7 +133,7 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
} else if ( isHeaderLine == 0 && (c == ' ' || c == '\t' ) && index > 0) { /* parse token when reaching a space or tab, unless buffer is empty */
parseToken = 1;
} else if (c != ' ' && c != '\t' ) { /* build up the token by copying a character */
- token[index] = c;
+ scheduleID->token[index] = c;
index++;
}
@@ -123,19 +141,17 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
/* Parse a token if needed. */
if (parseToken == 1 && index > 0) {
/* shouldn't require an overflow check since token is already checked */
- buff2 = (char*)calloc(sizeof(char), bufLen);
- if (buff2 == NULL)
- ModelicaFormatError("Failed to allocate memory for buff in WeeklySchedule.c.");
+
offset = 0;
- token[index] = '\0';
+ scheduleID->token[index] = '\0';
index++;
- tokenLen = strlen(token);
+ tokenLen = strlen(scheduleID->token);
index = 0;
/* ModelicaFormatWarning("Parsing token %s", token);*/
- if (foundHeader == 0 && strcmp("double", token) == 0) {
+ if (foundHeader == 0 && strcmp("double", scheduleID->token) == 0) {
/* we found a header line, we expect a specific format after the whitespace */
isHeaderLine = 1;
foundHeader = 1;
@@ -144,105 +160,140 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
int ncharsRow;
int ncharsCol;
- if (strncmp("tab1(", token, 4) != 0) {
+ if (strncmp("tab1(", scheduleID->token, 4) != 0) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Incorrect header when reading weekly schedule '%s'. It should start with 'tab1('.", name);
}
- source = token + 5;
+ source = scheduleID->token + 5;
ncharsRow = strcspn(source, ",");
if (tokenLen == ncharsRow + 5 ) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Incorrect header when reading weekly schedule '%s'. No comma was found in the header.", name);
}
- strncpy(buff2, source, ncharsRow);
- buff2[ncharsRow] = '\0';
+ strncpy(scheduleID->buff2, source, ncharsRow);
+ scheduleID->buff2[ncharsRow] = '\0';
- if (sscanf(buff2, "%i", &scheduleID->n_rows_in) != 1) {
- ModelicaFormatError("Error in intenger conversion in header while parsing %s in weekly schedule '%s'.", buff2, name);
+ if (sscanf(scheduleID->buff2, "%i", &scheduleID->n_rows_in) != 1) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Error in intenger conversion in header while parsing %s in weekly schedule '%s'.", scheduleID->buff2, name);
}
source = source + ncharsRow + 1;
ncharsCol = strcspn(source, ")");
if (tokenLen == ncharsCol + ncharsRow + 5 + 1) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Incorrect header when reading weekly schedule '%s'. No closing bracket was found in the header.", name);
} else if (tokenLen > ncharsCol + ncharsRow + 5 + 1 + 1) {
- ModelicaFormatError("Incorrect header when reading weekly schedule '%s'. It has trailing characters: '%s'.", name, token + ncharsRow + ncharsCol + 7);
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Incorrect header when reading weekly schedule '%s'. It has trailing characters: '%s'.", name, scheduleID->token + ncharsRow + ncharsCol + 7);
}
- strncpy(buff2, source, ncharsCol);
- buff2[ncharsCol] = '\0';
- if (sscanf(buff2, "%i", &scheduleID->n_cols_in) != 1) {
- ModelicaFormatError("Error in integer conversion in header while parsing %s in weekly schedule '%s'..", buff2, name);
+ strncpy(scheduleID->buff2, source, ncharsCol);
+ scheduleID->buff2[ncharsCol] = '\0';
+ if (sscanf(scheduleID->buff2, "%i", &scheduleID->n_cols_in) != 1) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Error in integer conversion in header while parsing %s in weekly schedule '%s'..", scheduleID->buff2, name);
}
if (scheduleID->n_cols_in < 2) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Illegal number of columns '%i' when reading weekly schedule '%s'.", scheduleID->n_cols_in, name);
}
if (scheduleID->n_rows_in < 1) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Illegal number of rows '%i' when reading weekly schedule '%s'.", scheduleID->n_rows_in, name);
}
isHeaderLine = 0;
foundHeader = 1;
- rules = (TimeDataTuple**)calloc(sizeof(TimeDataTuple *), scheduleID->n_rows_in);
- if ( rules == NULL)
+ scheduleID->rules = (TimeDataTuple**)calloc(sizeof(TimeDataTuple *), scheduleID->n_rows_in);
+ if ( scheduleID->rules == NULL){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to allocate memory for rules in WeeklySchedule.c.");
+ }
n_rulesInMem = scheduleID->n_rows_in;
} else if (foundHeader == 0) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Illegal file format, no header was found when reading weekly schedule '%s'.", name);
} else if (tokensInLine == 0) {
/* 0 tokens have been found on this line, so we're parsing a date/time */
- const int ncharsDays = strcspn(token, ":");
+ const int ncharsDays = strcspn(scheduleID->token, ":");
timeStamp = 0;
if (tokenLen != ncharsDays) {
double val;
- const int ncharsHour = strcspn(token + ncharsDays + 1, ":");
-
- strncpy(buff2, token + ncharsDays + 1, ncharsHour);
- buff2[ncharsHour] = '\0';
- if (sscanf(buff2, "%lf", &val) != 1) {
- ModelicaFormatError("Error in float conversion in hours when reading weekly schedule '%s'. Found token %s with length %i", name, buff2, ncharsHour);
+ const int ncharsHour = strcspn(scheduleID->token + ncharsDays + 1, ":");
+
+ strncpy(scheduleID->buff2, scheduleID->token + ncharsDays + 1, ncharsHour);
+ scheduleID->buff2[ncharsHour] = '\0';
+ if (sscanf(scheduleID->buff2, "%lf", &val) != 1) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Error in float conversion in hours when reading weekly schedule '%s'. Found token %s with length %i", name, scheduleID->buff2, ncharsHour);
}
if (val > 24 || val < 0) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Unexpected value for hour: '%f' when reading weekly schedule '%s', should be between 0 and 24.", val, name);
}
timeStamp += val * 3600;
if (tokenLen != ncharsHour + ncharsDays + 1) {
- const int ncharsMinutes = strcspn(token + ncharsDays + ncharsHour + 2, ":");
- strncpy(buff2, token + ncharsDays + ncharsHour + 2, ncharsMinutes);
- buff2[ncharsMinutes] = '\0';
- if (sscanf(buff2, "%lf", &val) != 1) {
+ const int ncharsMinutes = strcspn(scheduleID->token + ncharsDays + ncharsHour + 2, ":");
+ strncpy(scheduleID->buff2, scheduleID->token + ncharsDays + ncharsHour + 2, ncharsMinutes);
+ scheduleID->buff2[ncharsMinutes] = '\0';
+ if (sscanf(scheduleID->buff2, "%lf", &val) != 1) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Error in float conversion in minutes when reading weekly schedule '%s'.", name);
}
if (val > 60 || val < 0) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Unexpected value for minute: '%f' when reading weekly schedule '%s', should be between 0 and 60.", val, name);
}
timeStamp += val * 60;
if (tokenLen != ncharsMinutes + ncharsHour + ncharsDays + 2) {
const int ncharsSeconds = tokenLen - ncharsMinutes - ncharsHour - ncharsDays - 2;
- strncpy(buff2, token + ncharsDays + ncharsHour + ncharsMinutes + 3, ncharsSeconds);
- buff2[ncharsSeconds] = '\0';
- if (sscanf(buff2, "%lf", &val) != 1) {
+ strncpy(scheduleID->buff2, scheduleID->token + ncharsDays + ncharsHour + ncharsMinutes + 3, ncharsSeconds);
+ scheduleID->buff2[ncharsSeconds] = '\0';
+ if (sscanf(scheduleID->buff2, "%lf", &val) != 1) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Error in float conversion in seconds when reading weekly schedule '%s'.", name);
}
if (val > 60 || val < 0) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Unexpected value for seconds: '%f' when reading weekly schedule '%s', should be between 0 and 60.", val, name);
}
timeStamp += val;
}
}
}
- strncpy(buff2, token, ncharsDays);
- buff2[ncharsDays] = '\0';
+ strncpy(scheduleID->buff2, scheduleID->token, ncharsDays);
+ scheduleID->buff2[ncharsDays] = '\0';
/* loop over all days (comma separated) and for each date, add a rule */
while ( 1 ) {
- char * startIndex = buff2 + offset;
+ char * startIndex = scheduleID->buff2 + offset;
double t_day, time_i;
int nchars = strcspn(startIndex, ",");
if (nchars != 3 ) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Unexpected day format when reading weekly schedule '%s': %s.", name, startIndex);
}
@@ -261,30 +312,42 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
} else if (strncmp("sun", startIndex, 3) == 0) {
t_day = 6 * 3600 * 24;
} else {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Unexpected day format when parsing weekday '%s': %s.", name, startIndex);
}
/* expand the memory if the initially assigned memory block does not suffice*/
if (rule_i >= n_rulesInMem) {
n_rulesInMem += scheduleID->n_rows_in;
- rules = (TimeDataTuple**)realloc(rules, sizeof(TimeDataTuple*) * n_rulesInMem);
- if (rules == NULL) {
+ scheduleID->rules = (TimeDataTuple**)realloc(scheduleID->rules, sizeof(TimeDataTuple*) * n_rulesInMem);
+ if (scheduleID->rules == NULL) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to reallocate memory when reading weekly schedule '%s'.", name);
}
}
time_i = timeStamp + t_day;
- rules[rule_i] = (TimeDataTuple*)calloc(sizeof(TimeDataTuple), 1);
- if ( rules[rule_i] == NULL)
+ scheduleID->rules[rule_i] = (TimeDataTuple*)calloc(sizeof(TimeDataTuple), 1);
+ if ( scheduleID->rules[rule_i] == NULL){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to allocate memory for rules[rule_i] in WeeklySchedule.c.");
- rules[rule_i]->time = time_i;
- rules[rule_i]->data = (double*)calloc(sizeof(double), (scheduleID->n_cols_in - 1));
- if ( rules[rule_i]->data == NULL)
+ }
+ scheduleID->n_allocatedRules = rule_i;
+
+ scheduleID->rules[rule_i]->time = time_i;
+ scheduleID->rules[rule_i]->data = (double*)calloc(sizeof(double), (scheduleID->n_cols_in - 1));
+ if ( scheduleID->rules[rule_i]->data == NULL){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to allocate memory for rules[rule_i]->data in WeeklySchedule.c.");
- rule_i++;
+ }
+ scheduleID->n_allocatedRulesData = rule_i;
+ rule_i++;
n_rulesInRow++;
- n_rowsUnpacked++;
if (offset == 0) /* only for the first rule in this row*/
n_rowsPacked++;
@@ -300,30 +363,37 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
/* a token has been found on this line before, so we're parsing some numerical data*/
if (tokensInLine >= scheduleID->n_cols_in) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Too many columns on row %i when reading weekly schedule '%s'.", line, name);
}
- if (sscanf(token, "%lf", &val) != 1) {
- if (token[0] == '-') {
+ if (sscanf(scheduleID->token, "%lf", &val) != 1) {
+ if (scheduleID->token[0] == '-') {
val = HUGE_VAL; /*convert the wildcard in a double representation*/
} else {
- ModelicaFormatError("Invalid format for float %s when reading weekly schedule '%s'.", token, name);
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Invalid format for float %s when reading weekly schedule '%s'.", scheduleID->token, name);
}
}
/* Set the data for all rules that result from this row.*/
for (i = rule_i - n_rulesInRow; i < rule_i; ++i) {
- rules[i]->data[tokensInLine - 1] = val;
+ scheduleID->rules[i]->data[tokensInLine - 1] = val;
}
tokensInLine++;
} else {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Logic error when reading weekly schedule '%s'.", name); /*should not be able to end up here*/
}
- free(buff2);
}
if (c == '\n') { /*reset some internal variables*/
if (tokensInLine > 0 && tokensInLine != scheduleID->n_cols_in) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Incorrect number of columns on line %i when reading weekly schedule '%s'.", line, name);
}
line++;
@@ -333,29 +403,41 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
}
}
}
+
if (tableOnFile){
- fclose(fp);
+ fclose(scheduleID->fp);
}
if (n_newLines==0){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("In weekly schedule '%s': The provided %s is incorrectly formatted since it does not contain newline characters.", name, tableOnFile ? "file": "string parameter");
}
if (n_rowsPacked != scheduleID->n_rows_in) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Incorrect number of rows when reading weekly schedule '%s': %i instead of %i.", name, n_rowsPacked, scheduleID->n_rows_in);
}
- if (scheduleID->n_cols_in < 1)
+ if (scheduleID->n_cols_in < 1){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("The number of columns in the weekly schedule '%s' is %i, which is too small. ", name, scheduleID->n_cols_in);
+ }
/* sort all data by time stamp*/
- qsort(rules, rule_i, sizeof(TimeDataTuple*), cmpfun);
+ qsort(scheduleID->rules, rule_i, sizeof(TimeDataTuple*), cmpfun);
{
/* working vector with zero initial value*/
- lastData = (double*)calloc(sizeof(double), scheduleID->n_cols_in - 1);
- if (lastData == NULL)
+ scheduleID->lastData = (double*)calloc(sizeof(double), scheduleID->n_cols_in - 1);
+ if (scheduleID->lastData == NULL){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to allocate memory for lastData in WeeklySchedule.c., scheduleID->n_cols_in -1 = %d", scheduleID->n_cols_in - 1);
- memset(lastData, (char)(double)0, scheduleID->n_cols_in - 1); /* set vector to zero initial guess*/
+ }
+
+ memset(scheduleID->lastData, (char)(double)0, scheduleID->n_cols_in - 1); /* set vector to zero initial guess*/
/* Loop over all data and fill in wildcards using the last preceeding value.*/
/* This may wrap back to the end of last week, therefore loop the data twice.*/
@@ -364,41 +446,60 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
for (i = 0; i < 2; ++i) {
for (j = 0; j < rule_i; ++j) {
for (k = 0; k < scheduleID->n_cols_in - 1; ++k) {
- if ( rules[j]->data[k] != HUGE_VAL ) {
- lastData[k] = rules[j]->data[k];
+ if ( scheduleID->rules[j]->data[k] != HUGE_VAL ) {
+ scheduleID->lastData[k] = scheduleID->rules[j]->data[k];
} else if (i > 0) {
/* only on the second pass, since otherwise the default value is filled in permanently and
information from the back of the domain can't be recycled */
- rules[j]->data[k] = lastData[k];
+ scheduleID->rules[j]->data[k] = scheduleID->lastData[k];
}
}
}
}
- free(lastData);
}
/* store data for later use */
scheduleID->t_offset = t_offset;
- scheduleID->n_rowsUnpacked = n_rowsUnpacked;
scheduleID->previousIndex = 0;
- scheduleID->schedule = rules;
scheduleID->previousTimestamp = HUGE_VAL;
- free(token);
+ weeklyScheduleFreeInit(scheduleID);
return (void*) scheduleID;
}
+void weeklyScheduleFreeInit(void * ID) {
+ WeeklySchedule* scheduleID = (WeeklySchedule*)ID;
+
+ if (scheduleID->lastData != NULL)
+ free(scheduleID->lastData);
+
+ if (scheduleID->token != NULL)
+ free(scheduleID->token);
+
+ if (scheduleID->fp != NULL)
+ fclose(scheduleID->fp);
+
+ if (scheduleID->buff2 != NULL)
+ free(scheduleID->buff2);
+
+}
+
+
void weeklyScheduleFree(void * ID) {
WeeklySchedule* scheduleID = (WeeklySchedule*)ID;
int i;
- for (i = 0; i < scheduleID->n_rowsUnpacked; ++i) {
- free(scheduleID->schedule[i]->data);
- free(scheduleID->schedule[i]);
+ for (i = 0; i < scheduleID->n_allocatedRulesData; ++i) {
+ free(scheduleID->rules[i]->data);
+ }
+ for (i = 0; i < scheduleID->n_allocatedRules; ++i) {
+ free(scheduleID->rules[i]);
}
- free(scheduleID->schedule);
+ if (scheduleID->rules != NULL)
+ free(scheduleID->rules);
+
free(ID);
ID = NULL;
}
@@ -413,6 +514,8 @@ double getScheduleValue(void * ID, const int column, const double modelicaTime)
int i;
const int columnIndex = column - 1; /* Since we do not store the time indices in the data table */
+ /* Not using FreeModelicaFormatError() below since weeklyScheduleFreeInit() has been called at the end of the
+ initialization and Modelica will call weeklyScheduleFree() upon a call of ModelicaFormatError) */
if (column < 0 || column > scheduleID->n_cols_in - 1) {
ModelicaFormatError("The requested column index '%i' is outside of the table range.", column + 1);
}
@@ -423,28 +526,28 @@ double getScheduleValue(void * ID, const int column, const double modelicaTime)
if (time == scheduleID->previousTimestamp) {
i = scheduleID->previousIndex;
- } else if (time > scheduleID->schedule[scheduleID->previousIndex]->time) {
- for (i = scheduleID->previousIndex; i < scheduleID->n_rowsUnpacked - 1; i ++) {
- if (scheduleID->schedule[i + 1]->time > time) {
+ } else if (time > scheduleID->rules[scheduleID->previousIndex]->time) {
+ for (i = scheduleID->previousIndex; i < scheduleID->n_allocatedRules - 1; i ++) {
+ if (scheduleID->rules[i + 1]->time > time) {
break;
}
}
} else {
for (i = scheduleID->previousIndex; i > 0; i--) {
- if (scheduleID->schedule[i - 1]->time < time) {
+ if (scheduleID->rules[i - 1]->time < time) {
i = i - 1;
break;
}
}
/* if time is smaller than the first row, wrap back to the end of the week */
- if (i == 0 && scheduleID->schedule[0]->time > time) {
- i = scheduleID->n_rowsUnpacked - 1;
+ if (i == 0 && scheduleID->rules[0]->time > time) {
+ i = scheduleID->n_allocatedRules - 1;
}
}
scheduleID->previousIndex = i;
scheduleID->previousTimestamp = time;
- return scheduleID->schedule[i]->data[columnIndex];
+ return scheduleID->rules[i]->data[columnIndex];
}
#endif
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.h b/IBPSA/Resources/C-Sources/WeeklySchedule.h
index 4b52a6db2e..60b8528b89 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.h
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.h
@@ -16,6 +16,7 @@
#ifndef WEEKCAL_h
#define WEEKCAL_h
+
typedef struct TimeDataTuple {
double time; /* Time relative to monday midnight. */
double *data; /* Corresponding column data */
@@ -31,7 +32,14 @@ typedef struct WeeklySchedule {
double previousTimestamp; /* Time where the schedule was called the previous time */
int previousIndex; /* Index where the schedule was called the previous time */
- struct TimeDataTuple ** schedule;
+ int n_allocatedRules;
+ int n_allocatedRulesData;
+ double * lastData;
+ char * token;
+ FILE* fp;
+ char* buff2;
+ struct TimeDataTuple **rules;
+
} WeeklySchedule;
@@ -40,6 +48,8 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
void weeklyScheduleFree(void * ID);
+void weeklyScheduleFreeInit(void * ID);
+
double getScheduleValue(void * ID, const int column, const double time);
#endif
From 86793c71c3bf67e1e38ace972ea243a6cf2cc103 Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Sat, 30 Mar 2024 12:07:41 +0100
Subject: [PATCH 02/13] documentation for #1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index 14d5b35ee3..b01fff0b5d 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -514,7 +514,7 @@ double getScheduleValue(void * ID, const int column, const double modelicaTime)
int i;
const int columnIndex = column - 1; /* Since we do not store the time indices in the data table */
- /* Not using FreeModelicaFormatError() below since weeklyScheduleFreeInit() has been called at the end of the
+ /* Not calling weeklyScheduleFreeInit() or weeklyScheduleFree() since weeklyScheduleFreeInit() has already been called at the end of the
initialization and Modelica will call weeklyScheduleFree() upon a call of ModelicaFormatError) */
if (column < 0 || column > scheduleID->n_cols_in - 1) {
ModelicaFormatError("The requested column index '%i' is outside of the table range.", column + 1);
From 8e3bd4f1da2467f6220aad56353e5f78a3693b53 Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Sat, 30 Mar 2024 12:09:41 +0100
Subject: [PATCH 03/13] documentation for #1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 2 ++
IBPSA/Utilities/IO/Files/WeeklySchedule.mo | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index b01fff0b5d..bf0ea7301f 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -3,6 +3,8 @@
This code implements a weekly schedule.
Changelog:
+ March 30, 2024 by Filip Jorissen, Builtwins
+ Revisions for #1860 to avoid memory leaks when calling ModelicaFormatError.
May 25, 2022 by Michael Wetter, LBNL
Refactored to comply with C89.
March 9, 2022 by Filip Jorissen, KU Leuven
diff --git a/IBPSA/Utilities/IO/Files/WeeklySchedule.mo b/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
index caa626a0a0..2ef2a2194f 100644
--- a/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
+++ b/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
@@ -54,6 +54,10 @@ protected
revisions="
-
+March 30 2024, by Filip Jorissen:
+Avoiding memory leaks for #1860.
+
+-
April 10 2022, by Filip Jorissen:
Added parameter source implementation.
From 9d876f720ebabfb56b47425869b498c2d1566816 Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Sat, 30 Mar 2024 12:20:12 +0100
Subject: [PATCH 04/13] removed obsolete variable for #1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.h b/IBPSA/Resources/C-Sources/WeeklySchedule.h
index 60b8528b89..beae232558 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.h
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.h
@@ -27,7 +27,6 @@ typedef struct WeeklySchedule {
double t_offset; /* Time offset for monday, midnight. */
int n_rows_in; /* Number of input rows */
int n_cols_in; /* Number of input columns */
- int n_rowsUnpacked; /* Number of rows: number of rows after unpacking the date */
double previousTimestamp; /* Time where the schedule was called the previous time */
int previousIndex; /* Index where the schedule was called the previous time */
From 04988723d8b53a5cf59dd49f19853743eb304a24 Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Mon, 1 Apr 2024 22:27:49 +0200
Subject: [PATCH 05/13] added url in IBPSA/Utilities/IO/Files/WeeklySchedule.mo
for #1860
---
IBPSA/Utilities/IO/Files/WeeklySchedule.mo | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/IBPSA/Utilities/IO/Files/WeeklySchedule.mo b/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
index 2ef2a2194f..29006c0017 100644
--- a/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
+++ b/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
@@ -55,7 +55,7 @@ protected
-
March 30 2024, by Filip Jorissen:
-Avoiding memory leaks for #1860.
+Avoiding memory leaks for #1860.
-
April 10 2022, by Filip Jorissen:
From 17f57009fccb908848d8e945e5b63c2fe2aed06b Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Mon, 1 Apr 2024 22:27:58 +0200
Subject: [PATCH 06/13] buffer overflow check for #1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index bf0ea7301f..e1597c9791 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -176,6 +176,11 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
weeklyScheduleFree(scheduleID);
ModelicaFormatError("Incorrect header when reading weekly schedule '%s'. No comma was found in the header.", name);
}
+ if ( ncharsRow > bufLen - 2 ) {
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Header length exceeds buffer size.");
+ }
strncpy(scheduleID->buff2, source, ncharsRow);
scheduleID->buff2[ncharsRow] = '\0';
From 0ecdc2e8813cab7caf2eb330b9a3c1fa2c3bd43c Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Mon, 1 Apr 2024 22:48:31 +0200
Subject: [PATCH 07/13] attempted to add support for \r\n for #1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index e1597c9791..8cc9dd3ec4 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -108,7 +108,9 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
c = stringData[j]; /* read a character from the string */
j++;
}
- if ( c == EOF || c == '\0') {
+ if ( c == '\r' ){
+ continue;
+ } else if ( c == EOF || c == '\0') {
if (!tableOnFile && c == '\0'){
break;
}else if (tableOnFile && feof(scheduleID->fp)) {
From 94ffd94efd5f5f08c7be88b1f667aa6b62f1539a Mon Sep 17 00:00:00 2001
From: Michael Wetter
Date: Mon, 1 Apr 2024 16:20:41 -0700
Subject: [PATCH 08/13] Added escape to quotes
---
IBPSA/Utilities/IO/Files/WeeklySchedule.mo | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/IBPSA/Utilities/IO/Files/WeeklySchedule.mo b/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
index 29006c0017..5c50a78cba 100644
--- a/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
+++ b/IBPSA/Utilities/IO/Files/WeeklySchedule.mo
@@ -55,7 +55,7 @@ protected
-
March 30 2024, by Filip Jorissen:
-Avoiding memory leaks for #1860.
+Avoiding memory leaks for IBPSA, #1860.
-
April 10 2022, by Filip Jorissen:
@@ -94,7 +94,7 @@ The parameter columns
is used to specify which columns of the table
The first column is time, hence for the above example, set columns = {2}
.
-See IBPSA/Resources/Data/schedule.txt
+See IBPSA/Resources/Data/schedule.txt
for an example of the supported file format.
"),
From ac9c6e2302c831c4ebcbaf6997e2fc7424d49bc8 Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Tue, 2 Apr 2024 08:04:44 +0200
Subject: [PATCH 09/13] removed double fclose for #1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index 8cc9dd3ec4..15df770303 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -413,10 +413,6 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
}
}
- if (tableOnFile){
- fclose(scheduleID->fp);
- }
-
if (n_newLines==0){
weeklyScheduleFreeInit(scheduleID);
weeklyScheduleFree(scheduleID);
From 2bbcfbeaf815ff16eef76586c4f1d7825f492740 Mon Sep 17 00:00:00 2001
From: Michael Wetter
Date: Tue, 2 Apr 2024 14:20:58 -0700
Subject: [PATCH 10/13] Corrected function signature
Avoids a warning in OCT
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 6 +++---
IBPSA/Resources/C-Sources/WeeklySchedule.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index 15df770303..abe9d6c183 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -31,11 +31,11 @@ int cmpfun(const void * tuple1, const void * tuple2) {
return (time1 - time2);
}
-void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t_offset, char* stringData) {
+void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t_offset, const char* stringData) {
const int bufLen = 255;
WeeklySchedule* scheduleID = NULL;
-
+
int i = 0; /* iterator */
int j = 0; /* iterator */
int k = 0; /* iterator */
@@ -519,7 +519,7 @@ double getScheduleValue(void * ID, const int column, const double modelicaTime)
int i;
const int columnIndex = column - 1; /* Since we do not store the time indices in the data table */
- /* Not calling weeklyScheduleFreeInit() or weeklyScheduleFree() since weeklyScheduleFreeInit() has already been called at the end of the
+ /* Not calling weeklyScheduleFreeInit() or weeklyScheduleFree() since weeklyScheduleFreeInit() has already been called at the end of the
initialization and Modelica will call weeklyScheduleFree() upon a call of ModelicaFormatError) */
if (column < 0 || column > scheduleID->n_cols_in - 1) {
ModelicaFormatError("The requested column index '%i' is outside of the table range.", column + 1);
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.h b/IBPSA/Resources/C-Sources/WeeklySchedule.h
index beae232558..3a4105e261 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.h
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.h
@@ -43,7 +43,7 @@ typedef struct WeeklySchedule {
-void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t_offset, char* stringData);
+void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t_offset, const char* stringData);
void weeklyScheduleFree(void * ID);
From 411215d72751653314d35651e6f3b764fcb8679d Mon Sep 17 00:00:00 2001
From: Michael Wetter
Date: Tue, 2 Apr 2024 14:51:49 -0700
Subject: [PATCH 11/13] Added example with Windows line endings
---
IBPSA/Resources/Data/scheduleWindows.txt | 7 +++
...ation_WeeklyScheduleWindowsLineEndings.txt | 12 ++++
.../WeeklyScheduleWindowsLineEndings.mos | 2 +
.../WeeklyScheduleWindowsLineEndings.mo | 55 +++++++++++++++++++
.../Utilities/IO/Files/Validation/package.mo | 12 ++++
.../IO/Files/Validation/package.order | 1 +
IBPSA/Utilities/IO/Files/package.order | 1 +
7 files changed, 90 insertions(+)
create mode 100644 IBPSA/Resources/Data/scheduleWindows.txt
create mode 100644 IBPSA/Resources/ReferenceResults/Dymola/IBPSA_Utilities_IO_Files_Validation_WeeklyScheduleWindowsLineEndings.txt
create mode 100644 IBPSA/Resources/Scripts/Dymola/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mos
create mode 100644 IBPSA/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mo
create mode 100644 IBPSA/Utilities/IO/Files/Validation/package.mo
create mode 100644 IBPSA/Utilities/IO/Files/Validation/package.order
diff --git a/IBPSA/Resources/Data/scheduleWindows.txt b/IBPSA/Resources/Data/scheduleWindows.txt
new file mode 100644
index 0000000000..beabafdb0c
--- /dev/null
+++ b/IBPSA/Resources/Data/scheduleWindows.txt
@@ -0,0 +1,7 @@
+# Comments start with a #
+# The user is responsible for making sure that the header dimensions are correct
+double tab1(3,5) # Comments can be added at the end of a line for adding local documentation
+mon:0:0:10 - 3 1 -
+# Comments can be added in the table too
+tue,thu:20:30:59 123 - 45 -
+wed 12 1 4 -
diff --git a/IBPSA/Resources/ReferenceResults/Dymola/IBPSA_Utilities_IO_Files_Validation_WeeklyScheduleWindowsLineEndings.txt b/IBPSA/Resources/ReferenceResults/Dymola/IBPSA_Utilities_IO_Files_Validation_WeeklyScheduleWindowsLineEndings.txt
new file mode 100644
index 0000000000..cb6e638234
--- /dev/null
+++ b/IBPSA/Resources/ReferenceResults/Dymola/IBPSA_Utilities_IO_Files_Validation_WeeklyScheduleWindowsLineEndings.txt
@@ -0,0 +1,12 @@
+last-generated=2024-04-02
+statistics-simulation=
+{
+ "linear": " ",
+ "nonlinear": " ",
+ "numerical Jacobians": "0"
+}
+time=[-1e+04, 1e+06]
+weeSchLin.y[1]=[1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.2e+01, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02, 1.23e+02]
+weeSchLin.y[2]=[1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 3e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00]
+weeSchLin.y[3]=[4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 1e+00, 4.5e+01, 4.5e+01, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4e+00, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01, 4.5e+01]
+weeSchLin.y[4]=[0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00]
diff --git a/IBPSA/Resources/Scripts/Dymola/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mos b/IBPSA/Resources/Scripts/Dymola/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mos
new file mode 100644
index 0000000000..d90d3a8c46
--- /dev/null
+++ b/IBPSA/Resources/Scripts/Dymola/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mos
@@ -0,0 +1,2 @@
+simulateModel("IBPSA.Utilities.IO.Files.Validation.WeeklyScheduleWindowsLineEndings", startTime=-10000, stopTime=1000000, tolerance=1e-6, method="dassl", resultFile="WeeklyScheduleWindowsLineEndings");
+createPlot(id=1, position={15, 15, 592, 364}, y={"weeSchLin.y[1]", "weeSchLin.y[2]", "weeSchLin.y[3]", "weeSchLin.y[4]"}, range={-100000.0, 1000000.0, -20.0, 140.0}, grid=true, colors={{28,108,200}, {238,46,47}, {0,140,72}, {217,67,180}}, timeUnit="s");
diff --git a/IBPSA/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mo b/IBPSA/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mo
new file mode 100644
index 0000000000..30ab9564ad
--- /dev/null
+++ b/IBPSA/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mo
@@ -0,0 +1,55 @@
+within IBPSA.Utilities.IO.Files.Validation;
+model WeeklyScheduleWindowsLineEndings "Weekly schedule example"
+ extends Modelica.Icons.Example;
+ parameter String data = "double tab1(3,5) #test:
+mon:0:0:10 - 3 1 -
+tue,thu:20:30:59 123 - 45 -
+wed 12 1 4 -" "Contents of schedule.txt";
+ IBPSA.Utilities.IO.Files.WeeklySchedule weeSchLin(
+ columns={2,3,4,5},
+ tableOnFile=true,
+ fileName=Modelica.Utilities.Files.loadResource("modelica://IBPSA/Resources/Data/schedule.txt"),
+ t_offset=1e6) "Weekly schedule example using file data source"
+ annotation (Placement(transformation(extent={{-10,20},{10,40}})));
+
+ IBPSA.Utilities.IO.Files.WeeklySchedule weeSchWin(
+ columns={2,3,4,5},
+ tableOnFile=true,
+ fileName=Modelica.Utilities.Files.loadResource("modelica://IBPSA/Resources/Data/scheduleWindows.txt"),
+ t_offset=1e6) "Weekly schedule example using parameter data source"
+ annotation (Placement(transformation(extent={{-10,-32},{10,-12}})));
+ Diagnostics.AssertEquality assEqu[4](
+ each startTime=-10000,
+ each threShold=Modelica.Constants.small)
+ "Trigger an assertion if the outputs differ"
+ annotation (Placement(transformation(extent={{40,-10},{60,10}})));
+equation
+ connect(weeSchLin.y, assEqu.u1)
+ annotation (Line(points={{11,30},{24,30},{24,6},{38,6}}, color={0,0,127}));
+ connect(weeSchWin.y, assEqu.u2) annotation (Line(points={{11,-22},{24,-22},{24,
+ -6},{38,-6}}, color={0,0,127}));
+ annotation (
+ Documentation(info="
+
+Example for a weekly schedule that reads the schedule data from a file.
+There are two file readers, one reading a file with Windows line endings and the other with Linux line endings.
+
+",
+revisions="
+
+-
+April 2, 2024, by Michael Wetter:
+First implementation.
+This is for
+IBPSA, #1860.
+
+
+"),
+ experiment(
+ StartTime=-10000,
+ StopTime=1000000,
+ Tolerance=1e-06),
+ __Dymola_Commands(file=
+ "modelica://IBPSA/Resources/Scripts/Dymola/Utilities/IO/Files/Validation/WeeklyScheduleWindowsLineEndings.mos"
+ "Simulate and plot"));
+end WeeklyScheduleWindowsLineEndings;
diff --git a/IBPSA/Utilities/IO/Files/Validation/package.mo b/IBPSA/Utilities/IO/Files/Validation/package.mo
new file mode 100644
index 0000000000..4b75a38058
--- /dev/null
+++ b/IBPSA/Utilities/IO/Files/Validation/package.mo
@@ -0,0 +1,12 @@
+within IBPSA.Utilities.IO.Files;
+package Validation "Collection of models that validate the models that access files"
+ extends Modelica.Icons.ExamplesPackage;
+
+annotation (preferredView="info", Documentation(info="
+
+This package contains models that validate the models that access files.
+The examples plot various outputs. These model outputs are stored as reference data to
+allow continuous validation whenever models in the library change.
+
+"));
+end Validation;
diff --git a/IBPSA/Utilities/IO/Files/Validation/package.order b/IBPSA/Utilities/IO/Files/Validation/package.order
new file mode 100644
index 0000000000..a47e6a26b0
--- /dev/null
+++ b/IBPSA/Utilities/IO/Files/Validation/package.order
@@ -0,0 +1 @@
+WeeklyScheduleWindowsLineEndings
diff --git a/IBPSA/Utilities/IO/Files/package.order b/IBPSA/Utilities/IO/Files/package.order
index 6cbc46401f..41dcc44817 100644
--- a/IBPSA/Utilities/IO/Files/package.order
+++ b/IBPSA/Utilities/IO/Files/package.order
@@ -3,4 +3,5 @@ CombiTimeTableWriter
JSONWriter
WeeklySchedule
Examples
+Validation
BaseClasses
From a911c6ad6418dbdc80e2f0bc278439e472c66aeb Mon Sep 17 00:00:00 2001
From: Filip Jorissen
Date: Wed, 3 Apr 2024 13:13:05 +0200
Subject: [PATCH 12/13] fixed rule count and revised windows line endings check
for #1860
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index 15df770303..ae20c2a15f 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -50,7 +50,9 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
int n_rulesInRow = 0; /* number of rules that exist in the current row */
int n_rowsPacked = 0; /* number of rules */
int n_newLines = 0; /* number of newlines */
+ int mustHaveNewLine = 0;/* The next character must be a newline */
char c; /* the character that is being parsed in this iteration */
+
int parseToken = 0;
double timeStamp;
@@ -108,9 +110,7 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
c = stringData[j]; /* read a character from the string */
j++;
}
- if ( c == '\r' ){
- continue;
- } else if ( c == EOF || c == '\0') {
+ if ( c == EOF || c == '\0') {
if (!tableOnFile && c == '\0'){
break;
}else if (tableOnFile && feof(scheduleID->fp)) {
@@ -130,7 +130,14 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
if (c == '\n') { /* Check whether a token ends */
parseToken = 1;
+ mustHaveNewLine = 0;
n_newLines++;
+ } else if (mustHaveNewLine == 1){
+ weeklyScheduleFreeInit(scheduleID);
+ weeklyScheduleFree(scheduleID);
+ ModelicaFormatError("Error while reading weekly schedule '%s'. Inconsistent line endings: \\r must be followed by \\n.", name);
+ } else if (c == '\r') { /* Check whether a token ends */
+ mustHaveNewLine = 1;
} else if (comment == 1 || c == '#') {
comment = 1;
continue; /* ignore this character and the next characters until a newline is detected, then parse the token */
@@ -153,7 +160,7 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
tokenLen = strlen(scheduleID->token);
index = 0;
- /* ModelicaFormatWarning("Parsing token %s", token);*/
+ /* ModelicaFormatWarning("Parsing token %s", scheduleID->token); */
if (foundHeader == 0 && strcmp("double", scheduleID->token) == 0) {
/* we found a header line, we expect a specific format after the whitespace */
@@ -344,7 +351,7 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to allocate memory for rules[rule_i] in WeeklySchedule.c.");
}
- scheduleID->n_allocatedRules = rule_i;
+ scheduleID->n_allocatedRules++;
scheduleID->rules[rule_i]->time = time_i;
scheduleID->rules[rule_i]->data = (double*)calloc(sizeof(double), (scheduleID->n_cols_in - 1));
@@ -353,7 +360,7 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
weeklyScheduleFree(scheduleID);
ModelicaFormatError("Failed to allocate memory for rules[rule_i]->data in WeeklySchedule.c.");
}
- scheduleID->n_allocatedRulesData = rule_i;
+ scheduleID->n_allocatedRulesData++;
rule_i++;
n_rulesInRow++;
From f6d0326881c1b14dba4149cac15f58bbda8a379e Mon Sep 17 00:00:00 2001
From: Michael Wetter
Date: Wed, 3 Apr 2024 10:35:03 -0700
Subject: [PATCH 13/13] Removed trailing whitespace
---
IBPSA/Resources/C-Sources/WeeklySchedule.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/IBPSA/Resources/C-Sources/WeeklySchedule.c b/IBPSA/Resources/C-Sources/WeeklySchedule.c
index e546dbca88..ceb0397429 100644
--- a/IBPSA/Resources/C-Sources/WeeklySchedule.c
+++ b/IBPSA/Resources/C-Sources/WeeklySchedule.c
@@ -52,7 +52,7 @@ void* weeklyScheduleInit(const int tableOnFile, const char* name, const double t
int n_newLines = 0; /* number of newlines */
int mustHaveNewLine = 0;/* The next character must be a newline */
char c; /* the character that is being parsed in this iteration */
-
+
int parseToken = 0;
double timeStamp;