From da81bb7fba95fbfb4f9e5e4dee648a4127b9d0f7 Mon Sep 17 00:00:00 2001 From: Thomas Beutlich Date: Wed, 17 Jan 2024 01:55:30 +0100 Subject: [PATCH] Add ModelicaDuplicateString and ModelicaDuplicateStringWithErrorReturn (new in Modelica Language Specification version 3.5) (#3686) * Add ModelicaDuplicateString and ModelicaDuplicateStringWithErrorReturn * Utilize ModelicaDuplicateString and ModelicaDuplicateStringWithErrorReturn * Rename format specifying arguments * Utilize ModelicaDuplicateString and ModelicaDuplicateStringWithErrorReturn * Rely on assert Co-authored-by: Henrik Tidefelt * Update spelling Co-authored-by: Henrik Tidefelt * Call ModelicaError as stated in MLS 12.9.6.2 --------- Co-authored-by: Henrik Tidefelt --- .CI/Test/Common.c | 22 ++++++++++- .CI/Test/ModelicaUtilities.h | 36 ++++++++++++------ .../Resources/C-Sources/ModelicaInternal.c | 38 ++++++++----------- .../Resources/C-Sources/ModelicaStrings.c | 14 +++---- 4 files changed, 68 insertions(+), 42 deletions(-) diff --git a/.CI/Test/Common.c b/.CI/Test/Common.c index ce3a4b4715..e5b6600f82 100644 --- a/.CI/Test/Common.c +++ b/.CI/Test/Common.c @@ -2,10 +2,13 @@ #include #include #include +#include char* ModelicaAllocateString(size_t len) { void *data = malloc(len + 1); /* Never free'd in the test programs */ - assert(data); + if (NULL == data) { + ModelicaError("Failed to allocate string"); + } return data; } @@ -13,6 +16,23 @@ char* ModelicaAllocateStringWithErrorReturn(size_t len) { return malloc(len + 1); /* Never free'd in the test programs */ } +char* ModelicaDuplicateString(const char* str) { + void *data = malloc(strlen(str) + 1); /* Never free'd in the test programs */ + if (NULL == data) { + ModelicaError("Failed to duplicate string"); + } + strcpy(data, str); + return data; +} + +char* ModelicaDuplicateStringWithErrorReturn(const char* str) { + void *data = malloc(strlen(str) + 1); /* Never free'd in the test programs */ + if (NULL != data) { + strcpy(data, str); + } + return data; +} + void ModelicaMessage(const char *string) { printf("%s\n", string); } diff --git a/.CI/Test/ModelicaUtilities.h b/.CI/Test/ModelicaUtilities.h index be3e941e56..9d0ae886b3 100644 --- a/.CI/Test/ModelicaUtilities.h +++ b/.CI/Test/ModelicaUtilities.h @@ -131,19 +131,16 @@ void ModelicaMessage(const char *string); Output the message string (no format control). */ - -void ModelicaFormatMessage(const char *string, ...) MODELICA_FORMATATTR_PRINTF; +void ModelicaFormatMessage(const char *format, ...) MODELICA_FORMATATTR_PRINTF; /* Output the message under the same format control as the C-function printf. */ - -void ModelicaVFormatMessage(const char *string, va_list args) MODELICA_FORMATATTR_VPRINTF; +void ModelicaVFormatMessage(const char *format, va_list args) MODELICA_FORMATATTR_VPRINTF; /* Output the message under the same format control as the C-function vprintf. */ - MODELICA_NORETURN void ModelicaError(const char *string) MODELICA_NORETURNATTR; /* Output the error message string (no format control). This function @@ -156,32 +153,30 @@ void ModelicaWarning(const char *string); Output the warning message string (no format control). */ -void ModelicaFormatWarning(const char *string, ...) MODELICA_FORMATATTR_PRINTF; +void ModelicaFormatWarning(const char *format, ...) MODELICA_FORMATATTR_PRINTF; /* Output the warning message under the same format control as the C-function printf. */ -void ModelicaVFormatWarning(const char *string, va_list args) MODELICA_FORMATATTR_VPRINTF; +void ModelicaVFormatWarning(const char *format, va_list args) MODELICA_FORMATATTR_VPRINTF; /* Output the warning message under the same format control as the C-function vprintf. */ -MODELICA_NORETURN void ModelicaFormatError(const char *string, ...) MODELICA_NORETURNATTR MODELICA_FORMATATTR_PRINTF; +MODELICA_NORETURN void ModelicaFormatError(const char *format, ...) MODELICA_NORETURNATTR MODELICA_FORMATATTR_PRINTF; /* Output the error message under the same format control as the C-function printf. This function never returns to the calling function, but handles the error similarly to an assert in the Modelica code. */ - -MODELICA_NORETURN void ModelicaVFormatError(const char *string, va_list args) MODELICA_NORETURNATTR MODELICA_FORMATATTR_VPRINTF; +MODELICA_NORETURN void ModelicaVFormatError(const char *format, va_list args) MODELICA_NORETURNATTR MODELICA_FORMATATTR_VPRINTF; /* Output the error message under the same format control as the C-function vprintf. This function never returns to the calling function, but handles the error similarly to an assert in the Modelica code. */ - char* ModelicaAllocateString(size_t len); /* Allocate memory for a Modelica string which is used as return @@ -191,7 +186,6 @@ calling program, as for any other array. If an error occurs, this function does not return, but calls "ModelicaError". */ - char* ModelicaAllocateStringWithErrorReturn(size_t len); /* Same as ModelicaAllocateString, except that in case of error, the @@ -201,6 +195,24 @@ resources use ModelicaError or ModelicaFormatError to signal the error. */ +char* ModelicaDuplicateString(const char* str); +/* +Duplicate (= allocate memory and deep copy) a Modelica string which +is used as return argument of an external Modelica function. Note, +that the storage for string arrays (= pointer to string array) is still +provided by the calling program, as for any other array. If an error +occurs, this function does not return, but calls "ModelicaError". +*/ + +char* ModelicaDuplicateStringWithErrorReturn(const char* str); +/* +Same as ModelicaDuplicateString, except that in case of error, the +function returns 0. This allows the external function to close files +and free other open resources in case of error. After cleaning up +resources use, ModelicaError or ModelicaFormatError to signal +the error. +*/ + #if defined(__cplusplus) } #endif diff --git a/Modelica/Resources/C-Sources/ModelicaInternal.c b/Modelica/Resources/C-Sources/ModelicaInternal.c index 27141d758d..7ab2dc67c9 100644 --- a/Modelica/Resources/C-Sources/ModelicaInternal.c +++ b/Modelica/Resources/C-Sources/ModelicaInternal.c @@ -1,6 +1,6 @@ /* ModelicaInternal.c - External functions for Modelica.Utilities - Copyright (C) 2002-2023, Modelica Association and contributors + Copyright (C) 2002-2024, Modelica Association and contributors All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,6 +30,10 @@ */ /* Changelog: + Jan. 15, 2024: by Thomas Beutlich + Utilized ModelicaDuplicateString and + ModelicaDuplicateStringWithErrorReturn (ticket #3686) + Nov. 17, 2020: by Thomas Beutlich Fixed reading files with Unix-style line endings on Windows for ModelicaInternal_readLine/_readFile (ticket #3631) @@ -525,7 +529,7 @@ void ModelicaInternal_readDirectory(_In_z_ const char* directory, int nFiles, } /* Allocate Modelica memory for file/directory name and copy name */ - pName = ModelicaAllocateStringWithErrorReturn(strlen(pinfo->d_name)); + pName = ModelicaDuplicateStringWithErrorReturn(pinfo->d_name); if ( pName == NULL ) { errnoTemp = errno; closedir(pdir); @@ -538,7 +542,6 @@ void ModelicaInternal_readDirectory(_In_z_ const char* directory, int nFiles, directory, strerror(errnoTemp)); } } - strcpy(pName, pinfo->d_name); /* Save pointer to file */ files[iFiles] = pName; @@ -622,8 +625,7 @@ _Ret_z_ const char* ModelicaInternal_fullPathName(_In_z_ const char* name) { name, strerror(errno)); return ""; } - fullName = ModelicaAllocateString(strlen(tempName)); - strcpy(fullName, tempName); + fullName = ModelicaDuplicateString(tempName); ModelicaConvertToUnixDirectorySeparator(fullName); return fullName; #elif (_BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED || _POSIX_VERSION >= 200112L) @@ -635,8 +637,7 @@ _Ret_z_ const char* ModelicaInternal_fullPathName(_In_z_ const char* name) { if (tempName == NULL) { goto FALLBACK_getcwd; } - fullName = ModelicaAllocateString(strlen(tempName) + 1); - strcpy(fullName, tempName); + fullName = ModelicaDuplicateString(tempName); ModelicaConvertToUnixDirectorySeparator(fullName); /* Retain trailing slash to match _fullpath behaviour */ len = strlen(name); @@ -688,8 +689,7 @@ _Ret_z_ const char* ModelicaInternal_temporaryFileName(void) { ModelicaFormatError("Not possible to get temporary filename\n%s", strerror(errno)); return ""; } - fullName = ModelicaAllocateString(strlen(tempName)); - strcpy(fullName, tempName); + fullName = ModelicaDuplicateString(tempName); ModelicaConvertToUnixDirectorySeparator(fullName); return fullName; @@ -1011,12 +1011,11 @@ void ModelicaInternal_readFile(_In_z_ const char* fileName, while (iLines <= nLines) { readLine(&buf, &bufLen, fp); - line = ModelicaAllocateStringWithErrorReturn(strlen(buf)); + line = ModelicaDuplicateStringWithErrorReturn(buf); if ( line == NULL ) { goto Modelica_OOM_ERROR1; } - strcpy(line, buf); string[iLines - 1] = line; iLines++; } @@ -1063,12 +1062,11 @@ _Ret_z_ const char* ModelicaInternal_readLine(_In_z_ const char* fileName, } } - line = ModelicaAllocateStringWithErrorReturn(strlen(buf)); + line = ModelicaDuplicateStringWithErrorReturn(buf); if (line == NULL) { goto Modelica_OOM_ERROR2; } - strcpy(line, buf); CacheFileForReading(fp, fileName, lineNumber, buf, bufLen); *endOfFile = 0; return line; @@ -1078,8 +1076,7 @@ _Ret_z_ const char* ModelicaInternal_readLine(_In_z_ const char* fileName, fclose(fp); CloseCachedFile(fileName); *endOfFile = 1; - line = ModelicaAllocateString(0); - line[0] = '\0'; + line = ModelicaDuplicateString(""); return line; Modelica_OOM_ERROR2: @@ -1134,8 +1131,7 @@ _Ret_z_ const char* ModelicaInternal_getcwd(int dummy) { cwd = ""; } #endif - directory = ModelicaAllocateString(strlen(cwd)); - strcpy(directory, cwd); + directory = ModelicaDuplicateString(cwd); ModelicaConvertToUnixDirectorySeparator(directory); return directory; } @@ -1156,18 +1152,16 @@ void ModelicaInternal_getenv(_In_z_ const char* name, int convertToSlash, #endif if (value == NULL) { - result = ModelicaAllocateString(0); - result[0] = '\0'; + result = ModelicaDuplicateString(""); *exist = 0; } else { #if defined(_MSC_VER) && _MSC_VER >= 1400 - result = ModelicaAllocateStringWithErrorReturn(len); /* (len - 1) actually is sufficient */ + result = ModelicaDuplicateStringWithErrorReturn(value); if (result) { #else - result = ModelicaAllocateString(strlen(value)); + result = ModelicaDuplicateString(value); #endif - strcpy(result, value); if ( convertToSlash == 1 ) { ModelicaConvertToUnixDirectorySeparator(result); } diff --git a/Modelica/Resources/C-Sources/ModelicaStrings.c b/Modelica/Resources/C-Sources/ModelicaStrings.c index 5f9ae07e96..62d79679ca 100644 --- a/Modelica/Resources/C-Sources/ModelicaStrings.c +++ b/Modelica/Resources/C-Sources/ModelicaStrings.c @@ -1,6 +1,6 @@ /* ModelicaStrings.c - External functions for Modelica.Utilities.Strings - Copyright (C) 2002-2020, Modelica Association and contributors + Copyright (C) 2002-2024, Modelica Association and contributors All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,6 +30,10 @@ */ /* Changelog: + Jan. 15, 2024: by Thomas Beutlich + Utilized ModelicaDuplicateString and + ModelicaDuplicateStringWithErrorReturn (ticket #3686) + Mar. 15, 2020: by Thomas Beutlich Improved fault-tolerance of ModelicaStrings_substring w.r.t. index arguments (ticket #3503) @@ -231,9 +235,7 @@ void ModelicaStrings_scanIdentifier(_In_z_ const char* string, /* Token missing or not identifier. */ *nextIndex = startIndex; { - char* s = ModelicaAllocateString(0); - s[0] = '\0'; - *identifier = s; + *identifier = ModelicaDuplicateString(""); } return; } @@ -458,9 +460,7 @@ void ModelicaStrings_scanString(_In_z_ const char* string, int startIndex, Modelica_ERROR: { - char* s = ModelicaAllocateString(0); - s[0] = '\0'; - *result = s; + *result = ModelicaDuplicateString(""); } *nextIndex = startIndex; return;