ModelicaInternal.c 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. /* ModelicaInternal.c - External functions for Modelica.Utilities
  2. Copyright (C) 2002-2016, Modelica Association and DLR
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. 1. Redistributions of source code must retain the above copyright notice,
  7. this list of conditions and the following disclaimer.
  8. 2. Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  12. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  13. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  14. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  15. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  16. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  17. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  18. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  19. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  20. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21. */
  22. /* The functions in this file are mostly non-portable. The following #define's
  23. are used to define the system calls of the operating system
  24. _WIN32 : System calls of Windows'95, Windows'NT
  25. (Note, that these system calls allow both '/' and '\'
  26. as directory separator for input arguments. As return
  27. argument '\' is used).
  28. All system calls are from the library libc.a.
  29. _POSIX_ : System calls of POSIX
  30. _MSC_VER : Microsoft Visual C++
  31. __GNUC__ : GNU C compiler
  32. NO_FILE_SYSTEM : A file system is not present (e.g. on dSPACE or xPC).
  33. NO_PID : Function getpid is not present (e.g. on dSPACE)
  34. NO_TIME : Function gettimeofday is not present (e.g. on dSPACE)
  35. MODELICA_EXPORT: Prefix used for function calls. If not defined, blank is used
  36. Useful definitions:
  37. - "static" that is all functions become static
  38. (useful if file is included with other C-sources for an
  39. embedded system)
  40. - "__declspec(dllexport)" if included in a DLL and the
  41. functions shall be visible outside of the DLL
  42. Release Notes:
  43. Mar. 02, 2016: by Thomas Beutlich, ITI GmbH
  44. Fixed repeated opening of cached file in case of line miss in
  45. ModelicaStreams_openFileForReading (ticket #1939)
  46. Dec. 10, 2015: by Martin Otter, DLR
  47. Added flags NO_PID and NO_TIME (ticket #1805)
  48. Oct. 27, 2015: by Thomas Beutlich, ITI GmbH
  49. Added nonnull attributes/annotations (ticket #1436)
  50. Oct. 05, 2015: by Thomas Beutlich, ITI GmbH
  51. Added functions ModelicaInternal_getpid/_getTime from
  52. ModelicaRandom.c of https://github.com/DLR-SR/Noise
  53. (ticket #1662)
  54. Nov. 20, 2014: by Thomas Beutlich, ITI GmbH
  55. Fixed platform dependency of ModelicaInternal_readLine/_readFile
  56. (ticket #1580)
  57. Aug. 22, 2014: by Thomas Beutlich, ITI GmbH
  58. Fixed multi-threaded access of common/shared file cache
  59. (ticket #1556)
  60. Aug. 11, 2014: by Thomas Beutlich, ITI GmbH
  61. Increased cache size of opened files and made it
  62. thread-safe (ticket #1433)
  63. Made getenv/putenv thread-safe for Visual Studio 2005 and
  64. later (ticket #1433)
  65. May 21, 2013: by Martin Otter, DLR
  66. Included the improvements from DS Lund (ticket #1104):
  67. - Changed implementation of print to do nothing in case of
  68. missing file-system. Otherwise we just end up with an
  69. error message that is not written, and the failure in
  70. itself is not sufficiently fatal to just stop.
  71. - Caching when reading from file
  72. Mar, 26, 2013: by Martin Otter, DLR
  73. Changed type of variable valueStart from int to size_t
  74. (ticket #1032)
  75. Jan. 05, 2013: by Martin Otter, DLR
  76. Removed "static" declarations from the Modelica interface
  77. functions
  78. Sep. 26, 2004: by Martin Otter, DLR
  79. Added missing implementations, merged code from previous
  80. ModelicaFiles and clean-up of code
  81. Sep. 09, 2004: by Dag Bruck, Dynasim AB
  82. Further implementation and clean-up of code
  83. Aug. 24, 2004: by Martin Otter, DLR
  84. Adapted to Dymola 5.3 with minor improvements
  85. Jan. 07, 2002: by Martin Otter, DLR
  86. First version implemented:
  87. Only tested for _WIN32, but implemented all
  88. functions also for _POSIX_, with the exception of
  89. ModelicaInternal_getFullPath
  90. */
  91. #if !defined(MODELICA_EXPORT)
  92. #define MODELICA_EXPORT DYMOLA_STATIC
  93. #endif
  94. #if defined(linux)
  95. #define _POSIX_ 1
  96. /* for extra handling of realpath */
  97. #include <stdlib.h>
  98. #include <fcntl.h>
  99. #endif /* defined(linux) */
  100. #include <string.h>
  101. #include "ModelicaUtilities.h"
  102. /* The standard way to detect posix is to check _POSIX_VERSION,
  103. * which is defined in <unistd.h>
  104. */
  105. #if defined(__unix__) || defined(__linux__) || defined(__APPLE_CC__)
  106. #if !defined(NO_FILE_SYSTEM) && !defined(LABCAR)
  107. #include <unistd.h>
  108. #endif
  109. #endif
  110. #if !defined(_POSIX_) && defined(_POSIX_VERSION)
  111. #define _POSIX_ 1
  112. #endif
  113. static void ModelicaNotExistError(const char* name) {
  114. /* Print error message if a function is not implemented */
  115. ModelicaFormatError("C-Function \"%s\" is called\n"
  116. "but is not implemented for the actual environment\n"
  117. "(e.g., because there is no file system available on the machine\n"
  118. "as for dSPACE or xPC systems)", name);
  119. }
  120. #ifdef NO_FILE_SYSTEM
  121. MODELICA_EXPORT void ModelicaInternal_mkdir(const char* directoryName) {
  122. ModelicaNotExistError("ModelicaInternal_mkdir"); }
  123. MODELICA_EXPORT void ModelicaInternal_rmdir(const char* directoryName) {
  124. ModelicaNotExistError("ModelicaInternal_rmdir"); }
  125. MODELICA_EXPORT int ModelicaInternal_stat(const char* name) {
  126. ModelicaNotExistError("ModelicaInternal_stat"); return 0; }
  127. MODELICA_EXPORT void ModelicaInternal_rename(const char* oldName, const char* newName) {
  128. ModelicaNotExistError("ModelicaInternal_rename"); }
  129. MODELICA_EXPORT void ModelicaInternal_removeFile(const char* file) {
  130. ModelicaNotExistError("ModelicaInternal_removeFile"); }
  131. MODELICA_EXPORT void ModelicaInternal_copyFile(const char* oldFile, const char* newFile) {
  132. ModelicaNotExistError("ModelicaInternal_copyFile"); }
  133. MODELICA_EXPORT void ModelicaInternal_readDirectory(const char* directory, int nFiles, const char* files[]) {
  134. ModelicaNotExistError("ModelicaInternal_readDirectory"); }
  135. MODELICA_EXPORT int ModelicaInternal_getNumberOfFiles(const char* directory) {
  136. ModelicaNotExistError("ModelicaInternal_getNumberOfFiles"); return 0; }
  137. MODELICA_EXPORT const char* ModelicaInternal_fullPathName(const char* name) {
  138. ModelicaNotExistError("ModelicaInternal_fullPathName"); return 0; }
  139. MODELICA_EXPORT const char* ModelicaInternal_temporaryFileName(void) {
  140. ModelicaNotExistError("ModelicaInternal_temporaryFileName"); return 0; }
  141. MODELICA_EXPORT void ModelicaInternal_print(const char* string, const char* fileName) {
  142. if ( fileName[0] == '\0' ) {
  143. /* Write string to terminal */
  144. ModelicaFormatMessage("%s\n", string);
  145. }
  146. return; }
  147. MODELICA_EXPORT int ModelicaInternal_countLines(const char* fileName) {
  148. ModelicaNotExistError("ModelicaInternal_countLines"); return 0; }
  149. MODELICA_EXPORT void ModelicaInternal_readFile(const char* fileName, const char* string[], size_t nLines) {
  150. ModelicaNotExistError("ModelicaInternal_readFile"); }
  151. MODELICA_EXPORT const char* ModelicaInternal_readLine(const char* fileName, int lineNumber, int* endOfFile) {
  152. ModelicaNotExistError("ModelicaInternal_readLine"); return 0; }
  153. MODELICA_EXPORT void ModelicaInternal_chdir(const char* directoryName) {
  154. ModelicaNotExistError("ModelicaInternal_chdir"); }
  155. MODELICA_EXPORT const char* ModelicaInternal_getcwd(int dummy) {
  156. ModelicaNotExistError("ModelicaInternal_getcwd"); return 0; }
  157. MODELICA_EXPORT void ModelicaInternal_getenv(const char* name, int convertToSlash, const char** content, int* exist) {
  158. ModelicaNotExistError("ModelicaInternal_getenv"); }
  159. MODELICA_EXPORT void ModelicaInternal_setenv(const char* name, const char* value, int convertFromSlash) {
  160. ModelicaNotExistError("ModelicaInternal_setenv"); }
  161. #else
  162. #define uthash_fatal(msg) ModelicaFormatMessage("Error: %s\n", msg); break
  163. #include "uthash.h"
  164. #include "gconstructor.h"
  165. #include <stdio.h>
  166. #include <stdlib.h>
  167. #include <errno.h>
  168. #if defined(__WATCOMC__)
  169. #include <direct.h>
  170. #include <sys/types.h>
  171. #include <sys/stat.h>
  172. #elif defined(__BORLANDC__)
  173. #include <direct.h>
  174. #include <sys/types.h>
  175. #include <sys/stat.h>
  176. #include <dirent.h>
  177. #elif defined(_WIN32) && (defined(_MSC_VER) || defined(__GNUC__) && defined(DYMOSIM))
  178. #include <direct.h>
  179. #include <sys/types.h>
  180. #include <sys/stat.h>
  181. #if defined(__MINGW32__) || defined(__CYGWIN__) /* MinGW and Cygwin have dirent.h */
  182. #include <dirent.h>
  183. #else /* include the opendir/readdir/closedir implementation for _WIN32 */
  184. #include "win32_dirent.c"
  185. #endif
  186. #elif defined(_POSIX_) || defined(__GNUC__)
  187. #include <dirent.h>
  188. #include <unistd.h>
  189. #include <sys/types.h>
  190. #include <sys/stat.h>
  191. #endif
  192. /*
  193. * Non-null pointers and esp. null-terminated strings need to be passed to
  194. * external functions.
  195. *
  196. * The following macros handle nonnull attributes for GNU C and Microsoft SAL.
  197. */
  198. #ifndef MODELICA_NONNULLATTR
  199. #if defined(__GNUC__)
  200. #define MODELICA_NONNULLATTR __attribute__((nonnull))
  201. #if defined(__GNUC_MINOR__) && (__GNUC__ > 3 && __GNUC_MINOR__ > 8)
  202. #define MODELICA_RETURNNONNULLATTR __attribute__((returns_nonnull))
  203. #else
  204. #define MODELICA_RETURNNONNULLATTR
  205. #endif
  206. #elif defined(__ATTR_SAL)
  207. #define MODELICA_NONNULLATTR
  208. #define MODELICA_RETURNNONNULLATTR _Ret_z_ /* _Ret_notnull_ and null-terminated */
  209. #else
  210. #define MODELICA_NONNULLATTR
  211. #define MODELICA_RETURNNONNULLATTR
  212. #endif
  213. #if !defined(__ATTR_SAL) || defined(__MINGW32__)
  214. #define _In_z_
  215. #define _Out_
  216. #endif
  217. #endif /* #ifndef MODELICA_NONNULLATTR */
  218. MODELICA_EXPORT void ModelicaInternal_mkdir(_In_z_ const char* directoryName) MODELICA_NONNULLATTR;
  219. MODELICA_EXPORT void ModelicaInternal_rmdir(_In_z_ const char* directoryName) MODELICA_NONNULLATTR;
  220. MODELICA_EXPORT int ModelicaInternal_stat(_In_z_ const char* name) MODELICA_NONNULLATTR;
  221. MODELICA_EXPORT void ModelicaInternal_rename(_In_z_ const char* oldName,
  222. _In_z_ const char* newName) MODELICA_NONNULLATTR;
  223. MODELICA_EXPORT void ModelicaInternal_removeFile(_In_z_ const char* file) MODELICA_NONNULLATTR;
  224. MODELICA_EXPORT void ModelicaInternal_copyFile(_In_z_ const char* oldFile,
  225. _In_z_ const char* newFile) MODELICA_NONNULLATTR;
  226. MODELICA_EXPORT void ModelicaInternal_readDirectory(_In_z_ const char* directory, int nFiles,
  227. _Out_ const char** files) MODELICA_NONNULLATTR;
  228. MODELICA_EXPORT int ModelicaInternal_getNumberOfFiles(_In_z_ const char* directory) MODELICA_NONNULLATTR;
  229. MODELICA_EXPORT MODELICA_RETURNNONNULLATTR const char* ModelicaInternal_fullPathName(_In_z_ const char* name) MODELICA_NONNULLATTR;
  230. MODELICA_EXPORT MODELICA_RETURNNONNULLATTR const char* ModelicaInternal_temporaryFileName(void);
  231. MODELICA_EXPORT void ModelicaStreams_closeFile(_In_z_ const char* fileName) MODELICA_NONNULLATTR;
  232. MODELICA_EXPORT void ModelicaInternal_print(_In_z_ const char* string,
  233. _In_z_ const char* fileName) MODELICA_NONNULLATTR;
  234. MODELICA_EXPORT int ModelicaInternal_countLines(_In_z_ const char* fileName) MODELICA_NONNULLATTR;
  235. MODELICA_EXPORT void ModelicaInternal_readFile(_In_z_ const char* fileName,
  236. _Out_ const char* string[], size_t nLines) MODELICA_NONNULLATTR;
  237. MODELICA_EXPORT MODELICA_RETURNNONNULLATTR const char* ModelicaInternal_readLine(_In_z_ const char* fileName,
  238. int lineNumber, _Out_ int* endOfFile) MODELICA_NONNULLATTR;
  239. MODELICA_EXPORT void ModelicaInternal_chdir(_In_z_ const char* directoryName) MODELICA_NONNULLATTR;
  240. MODELICA_EXPORT MODELICA_RETURNNONNULLATTR const char* ModelicaInternal_getcwd(int dummy);
  241. MODELICA_EXPORT void ModelicaInternal_getenv(_In_z_ const char* name, int convertToSlash,
  242. _Out_ const char** content, _Out_ int* exist) MODELICA_NONNULLATTR;
  243. MODELICA_EXPORT void ModelicaInternal_setenv(_In_z_ const char* name,
  244. _In_z_ const char* value, int convertFromSlash) MODELICA_NONNULLATTR;
  245. MODELICA_EXPORT void ModelicaInternal_getTime(_Out_ int* ms, _Out_ int* sec, _Out_ int* min, _Out_ int* hour,
  246. _Out_ int* mday, _Out_ int* mon, _Out_ int* year) MODELICA_NONNULLATTR;
  247. #if PATH_MAX > 1024
  248. #define BUFFER_LENGTH PATH_MAX
  249. #else
  250. #define BUFFER_LENGTH 1024
  251. #endif
  252. typedef enum {
  253. FileType_NoFile = 1,
  254. FileType_RegularFile,
  255. FileType_Directory,
  256. FileType_SpecialFile /* pipe, FIFO, device, etc. */
  257. } ModelicaFileType;
  258. /* Convert to Unix directory separators: */
  259. #if defined(_WIN32)
  260. static void ModelicaConvertToUnixDirectorySeparator(char* string) {
  261. /* Convert to Unix directory separators */
  262. char* c = string;
  263. while ( *c ) {
  264. if ( *c == '\\' ) {
  265. *c = '/';
  266. }
  267. c++;
  268. }
  269. }
  270. static void ModelicaConvertFromUnixDirectorySeparator(char* string) {
  271. /* Convert from Unix directory separators */
  272. char* c = string;
  273. while ( *c ) {
  274. if ( *c == '/' ) {
  275. *c = '\\';
  276. }
  277. c++;
  278. }
  279. }
  280. #else
  281. #define ModelicaConvertToUnixDirectorySeparator(string) ;
  282. #define ModelicaConvertFromUnixDirectorySeparator(string) ;
  283. #endif
  284. /* --------------------- Modelica_Utilities.Internal --------------------------------- */
  285. MODELICA_EXPORT void ModelicaInternal_mkdir(const char* directoryName) {
  286. /* Create directory */
  287. #if defined(__WATCOMC__) || defined(__LCC__)
  288. int result = mkdir(directoryName);
  289. #elif defined(__BORLANDC__) || defined(_WIN32)
  290. int result = _mkdir(directoryName);
  291. #elif defined(_POSIX_) || defined(__GNUC__)
  292. int result = mkdir(directoryName, S_IRUSR | S_IWUSR | S_IXUSR);
  293. #else
  294. int result = -1;
  295. ModelicaNotExistError("ModelicaInternal_mkdir");
  296. #endif
  297. if (result != 0) {
  298. ModelicaFormatError("Not possible to create new directory\n"
  299. "\"%s\":\n%s", directoryName, strerror(errno));
  300. }
  301. }
  302. MODELICA_EXPORT void ModelicaInternal_rmdir(const char* directoryName) {
  303. /* Remove directory */
  304. #if defined(__WATCOMC__) || defined(__LCC__) || defined(_POSIX_) || defined(__GNUC__)
  305. int result = rmdir(directoryName);
  306. #elif defined(__BORLANDC__) || defined(_WIN32)
  307. int result = _rmdir(directoryName);
  308. #else
  309. int result = -1;
  310. ModelicaNotExistError("ModelicaInternal_rmdir");
  311. #endif
  312. if (result != 0) {
  313. ModelicaFormatError("Not possible to remove directory\n"
  314. "\"%s\":\n%s", directoryName, strerror(errno));
  315. }
  316. }
  317. MODELICA_EXPORT int ModelicaInternal_stat(const char* name) {
  318. /* Inquire type of file */
  319. ModelicaFileType type = FileType_NoFile;
  320. #if defined(__WATCOMC__) || defined(__BORLANDC__)
  321. struct _stat fileInfo;
  322. if ( _stat(name, &fileInfo) != 0 ) {
  323. type = FileType_NoFile;
  324. }
  325. else if ( fileInfo.st_mode & S_IFREG ) {
  326. type = FileType_RegularFile;
  327. }
  328. else if ( fileInfo.st_mode & S_IFDIR ) {
  329. type = FileType_Directory;
  330. }
  331. else {
  332. type = FileType_SpecialFile;
  333. }
  334. #elif defined(_WIN32)
  335. struct _stat fileInfo;
  336. int statReturn;
  337. statReturn=_stat(name, &fileInfo);
  338. if (statReturn!=0) {
  339. /* For some reason _stat requires a:\ and a:\test1 and fails on a: and a:\test1\ */
  340. /* It could be handled in the Modelica code, but seems better to have here */
  341. if (strpbrk(name,"/\\")==0 && strchr(name,':')!=0 && strchr(name,':')[1]==0 && (strchr(name,':')-name)<40) {
  342. char name2[100];
  343. strcpy(name2,name);
  344. strcat(name2,"\\");
  345. statReturn=_stat(name2, &fileInfo);
  346. }
  347. }
  348. if ( statReturn != 0 ) {
  349. type = FileType_NoFile;
  350. }
  351. else if ( fileInfo.st_mode & S_IFREG ) {
  352. type = FileType_RegularFile;
  353. }
  354. else if ( fileInfo.st_mode & S_IFDIR ) {
  355. type = FileType_Directory;
  356. }
  357. else {
  358. type = FileType_SpecialFile;
  359. }
  360. #elif defined(_POSIX_) || defined(__GNUC__)
  361. struct stat fileInfo;
  362. int statReturn;
  363. statReturn=stat(name, &fileInfo);
  364. if ( statReturn != 0 ) {
  365. type = FileType_NoFile;
  366. }
  367. else if ( S_ISREG(fileInfo.st_mode) ) {
  368. type = FileType_RegularFile;
  369. }
  370. else if ( S_ISDIR(fileInfo.st_mode) ) {
  371. type = FileType_Directory;
  372. }
  373. else {
  374. type = FileType_SpecialFile;
  375. }
  376. #else
  377. ModelicaNotExistError("ModelicaInternal_stat");
  378. #endif
  379. return type;
  380. }
  381. MODELICA_EXPORT void ModelicaInternal_rename(const char* oldName, const char* newName) {
  382. /* Change the name of a file or of a directory */
  383. if ( rename(oldName, newName) != 0 ) {
  384. ModelicaFormatError("renaming \"%s\" to \"%s\" failed:\n%s",
  385. oldName, newName, strerror(errno));
  386. }
  387. }
  388. MODELICA_EXPORT void ModelicaInternal_removeFile(const char* file) {
  389. /* Remove file */
  390. if ( remove(file) != 0 ) {
  391. ModelicaFormatError("Not possible to remove file \"%s\":\n%s",
  392. file, strerror(errno));
  393. }
  394. }
  395. MODELICA_EXPORT void ModelicaInternal_copyFile(const char* oldFile, const char* newFile) {
  396. /* Copy file */
  397. #ifdef _WIN32
  398. const char* modeOld = "rb";
  399. const char* modeNew = "wb";
  400. #else
  401. const char* modeOld = "r";
  402. const char* modeNew = "w";
  403. #endif
  404. FILE* fpOld;
  405. FILE* fpNew;
  406. ModelicaFileType type;
  407. int c;
  408. /* Check file existence */
  409. type = (ModelicaFileType) ModelicaInternal_stat(oldFile);
  410. if ( type == FileType_NoFile ) {
  411. ModelicaFormatError("\"%s\" cannot be copied\nbecause it does not exist", oldFile);
  412. return;
  413. }
  414. else if ( type == FileType_Directory ) {
  415. ModelicaFormatError("\"%s\" cannot be copied\nbecause it is a directory", oldFile);
  416. return;
  417. }
  418. else if ( type == FileType_SpecialFile ) {
  419. ModelicaFormatError("\"%s\" cannot be copied\n"
  420. "because it is not a regular file", oldFile);
  421. return;
  422. }
  423. type = (ModelicaFileType) ModelicaInternal_stat(newFile);
  424. if ( type != FileType_NoFile ) {
  425. ModelicaFormatError("\"%s\" cannot be copied\nbecause the target "
  426. "\"%s\" exists", oldFile, newFile);
  427. return;
  428. }
  429. /* Copy file */
  430. fpOld = fopen(oldFile, modeOld);
  431. if ( fpOld == NULL ) {
  432. ModelicaFormatError("\"%s\" cannot be copied:\n%s", oldFile, strerror(errno));
  433. return;
  434. }
  435. fpNew = fopen(newFile, modeNew);
  436. if ( fpNew == NULL ) {
  437. fclose(fpOld);
  438. ModelicaFormatError("\"%s\" cannot be copied to \"%s\":\n%s",
  439. oldFile, newFile, strerror(errno));
  440. return;
  441. }
  442. while ( (c = getc(fpOld)) != EOF ) {
  443. putc(c, fpNew);
  444. }
  445. fclose(fpOld);
  446. fclose(fpNew);
  447. }
  448. MODELICA_EXPORT void ModelicaInternal_readDirectory(const char* directory, int nFiles,
  449. const char** files) {
  450. /* Get all file and directory names in a directory in any order
  451. (must be very careful, to call closedir if an error occurs)
  452. */
  453. #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_WIN32) || defined(_POSIX_) || defined(__GNUC__)
  454. int errnoTemp;
  455. int iFiles = 0;
  456. char *pName;
  457. struct dirent *pinfo;
  458. DIR* pdir;
  459. /* Open directory information inquiry */
  460. pdir = opendir(directory);
  461. if ( pdir == NULL ) {
  462. ModelicaFormatError("1: Not possible to get file names of \"%s\":\n%s",
  463. directory, strerror(errno));
  464. }
  465. /* Read file and directory names and store them in vector "files" */
  466. errno = 0;
  467. while ( (pinfo = readdir(pdir)) != NULL ) {
  468. if ( (strcmp(pinfo->d_name, "." ) != 0) &&
  469. (strcmp(pinfo->d_name, "..") != 0) ) {
  470. /* Check if enough space in "files" vector */
  471. if ( iFiles >= nFiles ) {
  472. closedir(pdir);
  473. ModelicaFormatError("Not possible to get file names of \"%s\":\n"
  474. "More files in this directory as reported by nFiles (= %i)",
  475. directory, nFiles);
  476. }
  477. /* Allocate Modelica memory for file/directory name and copy name */
  478. pName = ModelicaAllocateStringWithErrorReturn(strlen(pinfo->d_name));
  479. if ( pName == NULL ) {
  480. errnoTemp = errno;
  481. closedir(pdir);
  482. if ( errnoTemp == 0 ) {
  483. ModelicaFormatError("Not possible to get file names of \"%s\":\n"
  484. "Not enough storage", directory);
  485. }
  486. else {
  487. ModelicaFormatError("Not possible to get file names of \"%s\":\n%s",
  488. directory, strerror(errnoTemp));
  489. }
  490. }
  491. strcpy(pName, pinfo->d_name);
  492. /* Save pointer to file */
  493. files[iFiles] = pName;
  494. iFiles++;
  495. }
  496. }
  497. if ( errno != 0 ) {
  498. errnoTemp = errno;
  499. closedir(pdir);
  500. ModelicaFormatError("Not possible to get file names of \"%s\":\n%s",
  501. directory, strerror(errnoTemp));
  502. }
  503. /* Check, whether the whole "files" vector is filled and close inquiry */
  504. if ( iFiles != nFiles) {
  505. closedir(pdir);
  506. ModelicaFormatError("Not possible to get file names of \"%s\":\n"
  507. "Less files (= %d) found as defined by argument nNames (= %d)",
  508. directory, iFiles, nFiles);
  509. }
  510. if ( closedir(pdir) != 0 ) {
  511. ModelicaFormatError("Not possible to get file names of \"%s\":\n",
  512. directory, strerror(errno));
  513. }
  514. #else
  515. ModelicaNotExistError("ModelicaInternal_readDirectory");
  516. #endif
  517. }
  518. MODELICA_EXPORT int ModelicaInternal_getNumberOfFiles(const char* directory) {
  519. /* Get number of files and directories in a directory */
  520. #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_WIN32) || defined(_POSIX_) || defined(__GNUC__)
  521. int nFiles = 0;
  522. int errnoTemp;
  523. struct dirent *pinfo;
  524. DIR* pdir;
  525. pdir = opendir(directory);
  526. if ( pdir == NULL ) {
  527. goto Modelica_ERROR;
  528. }
  529. errno = 0;
  530. while ( (pinfo = readdir(pdir)) != NULL ) {
  531. if ( (strcmp(pinfo->d_name, "." ) != 0) &&
  532. (strcmp(pinfo->d_name, "..") != 0) ) {
  533. nFiles++;
  534. }
  535. }
  536. errnoTemp = errno;
  537. closedir(pdir);
  538. if ( errnoTemp != 0 ) {
  539. errno = errnoTemp;
  540. goto Modelica_ERROR;
  541. }
  542. return nFiles;
  543. Modelica_ERROR:
  544. ModelicaFormatError("Not possible to get number of files in \"%s\":\n%s",
  545. directory, strerror(errno));
  546. return 0;
  547. #else
  548. ModelicaNotExistError("ModelicaInternal_getNumberOfFiles");
  549. return 0;
  550. #endif
  551. }
  552. /* --------------------- Modelica_Utilities.Files ------------------------------------- */
  553. MODELICA_EXPORT const char* ModelicaInternal_fullPathName(const char* name) {
  554. /* Get full path name of file or directory */
  555. #if defined(_WIN32) || (_BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED || (_POSIX_VERSION >= 200112L))
  556. char* fullName;
  557. char localbuf[BUFFER_LENGTH];
  558. #if (_BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED || _POSIX_VERSION >= 200112L)
  559. /* realpath availability: 4.4BSD, POSIX.1-2001. Using the behaviour of NULL: POSIX.1-2008 */
  560. char* tempName = realpath(name, localbuf);
  561. if (tempName == NULL) {
  562. /* for non-existing files, at least handle the simple case where the directory path exists, but the file does not */
  563. /* create file temporarily */
  564. int fd = creat(name, 0);
  565. if (fd != -1) {
  566. tempName = realpath(name, localbuf);
  567. remove(tempName);
  568. }
  569. }
  570. #else
  571. char* tempName = _fullpath(localbuf, name, sizeof(localbuf));
  572. #endif
  573. if (tempName == NULL) {
  574. ModelicaFormatError("Not possible to construct full path name of \"%s\"\n%s",
  575. name, strerror(errno));
  576. return "";
  577. }
  578. fullName = ModelicaAllocateString(strlen(tempName));
  579. strcpy(fullName, tempName);
  580. ModelicaConvertToUnixDirectorySeparator(fullName);
  581. #elif defined(_POSIX_)
  582. char* fullName;
  583. char localbuf[BUFFER_LENGTH];
  584. /* No such system call in _POSIX_ available (except realpath above) */
  585. char* cwd = getcwd(localbuf, sizeof(localbuf));
  586. if (cwd == NULL) {
  587. ModelicaFormatError("Not possible to get current working directory:\n%s",
  588. strerror(errno));
  589. }
  590. fullName = ModelicaAllocateString(strlen(cwd) + strlen(name) + 1);
  591. if (name[0] != '/') {
  592. /* Any name beginning with "/" is regarded as already being a full path. */
  593. strcpy(fullName, cwd);
  594. strcat(fullName, "/");
  595. }
  596. strcat(fullName, name);
  597. #else
  598. char* fullName = "";
  599. ModelicaNotExistError("ModelicaInternal_fullPathName");
  600. #endif
  601. return fullName;
  602. }
  603. MODELICA_EXPORT const char* ModelicaInternal_temporaryFileName(void) {
  604. /* Get full path name of a temporary */
  605. char* fullName;
  606. char* tempName = tmpnam(NULL);
  607. if (tempName == NULL) {
  608. ModelicaFormatError("Not possible to get temporary filename\n%s", strerror(errno));
  609. return "";
  610. }
  611. fullName = ModelicaAllocateString(strlen(tempName));
  612. strcpy(fullName, tempName);
  613. ModelicaConvertToUnixDirectorySeparator(fullName);
  614. return fullName;
  615. }
  616. /* --------------------- Abstract data type for stream handles --------------------- */
  617. /* Improved for caching of the open files */
  618. typedef struct FileCache {
  619. char* fileName; /* Key = File name */
  620. FILE* fp /* File pointer */;
  621. int line;
  622. UT_hash_handle hh; /* Hashable structure */
  623. } FileCache;
  624. static FileCache* fileCache = NULL;
  625. #if defined(_POSIX_)
  626. #include <pthread.h>
  627. #if defined(G_HAS_CONSTRUCTORS)
  628. static pthread_mutex_t m;
  629. G_DEFINE_CONSTRUCTOR(initializeMutex)
  630. static void initializeMutex(void) {
  631. if (pthread_mutex_init(&m, NULL) != 0) {
  632. ModelicaError("Initialization of mutex failed\n");
  633. }
  634. }
  635. G_DEFINE_DESTRUCTOR(destroyMutex)
  636. static void destroyMutex(void) {
  637. if (pthread_mutex_destroy(&m) != 0) {
  638. ModelicaError("Destruction of mutex failed\n");
  639. }
  640. }
  641. #else
  642. static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
  643. #endif
  644. #define MUTEX_LOCK() pthread_mutex_lock(&m)
  645. #define MUTEX_UNLOCK() pthread_mutex_unlock(&m)
  646. #elif defined(_WIN32) && defined(G_HAS_CONSTRUCTORS)
  647. #if !defined(WIN32_LEAN_AND_MEAN)
  648. #define WIN32_LEAN_AND_MEAN
  649. #endif
  650. #include <Windows.h>
  651. static CRITICAL_SECTION cs;
  652. #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
  653. #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(initializeCS)
  654. #endif
  655. G_DEFINE_CONSTRUCTOR(initializeCS)
  656. static void initializeCS(void) {
  657. InitializeCriticalSection(&cs);
  658. }
  659. #ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA
  660. #pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(deleteCS)
  661. #endif
  662. G_DEFINE_DESTRUCTOR(deleteCS)
  663. static void deleteCS(void) {
  664. DeleteCriticalSection(&cs);
  665. }
  666. #define MUTEX_LOCK() EnterCriticalSection(&cs)
  667. #define MUTEX_UNLOCK() LeaveCriticalSection(&cs)
  668. #else
  669. #define MUTEX_LOCK()
  670. #define MUTEX_UNLOCK()
  671. #endif
  672. static void CacheFileForReading(FILE* fp, const char* fileName, int line) {
  673. FileCache* fv;
  674. if (fileName == NULL) {
  675. /* Do not add, close file */
  676. if (fp != NULL) {
  677. fclose(fp);
  678. }
  679. return;
  680. }
  681. MUTEX_LOCK();
  682. HASH_FIND(hh, fileCache, fileName, (unsigned)strlen(fileName), fv);
  683. if (fv != NULL) {
  684. fv->fp = fp;
  685. fv->line = line;
  686. }
  687. else {
  688. fv = (FileCache*)malloc(sizeof(FileCache));
  689. if (fv != NULL) {
  690. char* key = (char*)malloc((strlen(fileName) + 1)*sizeof(char));
  691. if (key != NULL) {
  692. strcpy(key, fileName);
  693. fv->fileName = key;
  694. fv->fp = fp;
  695. fv->line = line;
  696. HASH_ADD_KEYPTR(hh, fileCache, key, (unsigned)strlen(key), fv);
  697. }
  698. }
  699. }
  700. MUTEX_UNLOCK();
  701. }
  702. static void CloseCachedFile(const char* fileName) {
  703. FileCache* fv;
  704. MUTEX_LOCK();
  705. HASH_FIND(hh, fileCache, fileName, (unsigned)strlen(fileName), fv);
  706. if (fv != NULL) {
  707. if (fv->fp != NULL) {
  708. fclose(fv->fp);
  709. }
  710. free(fv->fileName);
  711. HASH_DEL(fileCache, fv);
  712. free(fv);
  713. }
  714. MUTEX_UNLOCK();
  715. }
  716. static FILE* ModelicaStreams_openFileForReading(const char* fileName, int line) {
  717. /* Open text file for reading */
  718. FILE* fp;
  719. int c = 1;
  720. FileCache* fv;
  721. MUTEX_LOCK();
  722. HASH_FIND(hh, fileCache, fileName, (unsigned)strlen(fileName), fv);
  723. /* Open file */
  724. if (fv != NULL) {
  725. /* Cached value */
  726. if (fv->fp != NULL) {
  727. if (line != 0 && line >= fv->line) {
  728. line -= fv->line;
  729. fp = fv->fp;
  730. }
  731. else {
  732. if ( fseek(fv->fp, 0L, SEEK_SET) == 0 ) {
  733. fp = fv->fp;
  734. }
  735. else {
  736. fclose(fv->fp);
  737. fp = NULL;
  738. }
  739. }
  740. fv->fp = NULL;
  741. }
  742. else {
  743. fp = NULL;
  744. }
  745. }
  746. else {
  747. fp = NULL;
  748. }
  749. MUTEX_UNLOCK();
  750. if (fp == NULL) {
  751. fp = fopen(fileName, "r");
  752. if ( fp == NULL ) {
  753. ModelicaFormatError("Not possible to open file \"%s\" for reading:\n"
  754. "%s\n", fileName, strerror(errno));
  755. }
  756. }
  757. while ( line != 0 && c != EOF ) {
  758. c = fgetc(fp);
  759. while ( c != '\n' && c != EOF ) {
  760. c = fgetc(fp);
  761. }
  762. line--;
  763. }
  764. return fp;
  765. }
  766. MODELICA_EXPORT void ModelicaStreams_closeFile(const char* fileName) {
  767. /* Close file */
  768. CloseCachedFile(fileName); /* Closes it */
  769. }
  770. static FILE* ModelicaStreams_openFileForWriting(const char* fileName) {
  771. /* Open text file for writing (with append) */
  772. FILE* fp;
  773. /* Check fileName */
  774. if ( strlen(fileName) == 0 ) {
  775. ModelicaError("fileName is an empty string.\n"
  776. "Opening of file is aborted\n");
  777. }
  778. /* Open file */
  779. ModelicaStreams_closeFile(fileName);
  780. fp = fopen(fileName, "a");
  781. if ( fp == NULL ) {
  782. ModelicaFormatError("Not possible to open file \"%s\" for writing:\n"
  783. "%s\n", fileName, strerror(errno));
  784. }
  785. return fp;
  786. }
  787. /* --------------------- Modelica_Utilities.Streams ----------------------------------- */
  788. MODELICA_EXPORT void ModelicaInternal_print(const char* string, const char* fileName) {
  789. /* Write string to terminal or to file */
  790. if ( fileName[0] == '\0' ) {
  791. /* Write string to terminal */
  792. ModelicaFormatMessage("%s\n", string);
  793. }
  794. else {
  795. /* Write string to file */
  796. FILE* fp = ModelicaStreams_openFileForWriting(fileName);
  797. if ( fputs(string,fp) < 0 ) {
  798. goto Modelica_ERROR2;
  799. }
  800. if ( fputs("\n",fp) < 0 ) {
  801. goto Modelica_ERROR2;
  802. }
  803. fclose(fp);
  804. return;
  805. Modelica_ERROR2:
  806. fclose(fp);
  807. ModelicaFormatError("Error when writing string to file \"%s\":\n"
  808. "%s\n", fileName, strerror(errno));
  809. }
  810. }
  811. MODELICA_EXPORT int ModelicaInternal_countLines(const char* fileName) {
  812. /* Get number of lines of a file */
  813. int c;
  814. int nLines = 0;
  815. int start_of_line = 1;
  816. /* If true, next character starts a new line. */
  817. FILE* fp = ModelicaStreams_openFileForReading(fileName, 0);
  818. /* Count number of lines */
  819. while ((c = fgetc(fp)) != EOF) {
  820. if (start_of_line) {
  821. nLines++;
  822. start_of_line = 0;
  823. }
  824. if (c == '\n') {
  825. start_of_line = 1;
  826. }
  827. }
  828. fclose(fp);
  829. return nLines;
  830. }
  831. MODELICA_EXPORT void ModelicaInternal_readFile(const char* fileName, const char* string[], size_t nLines) {
  832. /* Read file into string vector string[nLines] */
  833. FILE* fp = ModelicaStreams_openFileForReading(fileName, 0);
  834. char* line;
  835. size_t iLines;
  836. size_t nc;
  837. char localbuf[200]; /* To avoid fseek */
  838. /* Read data from file */
  839. iLines = 1;
  840. while ( iLines <= nLines ) {
  841. /* Determine length of next line */
  842. int offset = ftell(fp);
  843. size_t lineLen = 0;
  844. int c = fgetc(fp);
  845. int c2 = c;
  846. while ( c != '\n' && c != EOF ) {
  847. if (lineLen < sizeof(localbuf)) {
  848. localbuf[lineLen] = (char)c;
  849. }
  850. lineLen++;
  851. c2 = c;
  852. c = fgetc(fp);
  853. }
  854. if ( lineLen > 0 && c2 == '\r' ) {
  855. lineLen--;
  856. }
  857. /* Allocate storage for next line */
  858. line = ModelicaAllocateStringWithErrorReturn(lineLen);
  859. if ( line == NULL ) {
  860. fclose(fp);
  861. ModelicaFormatError("Not enough memory to allocate string for reading line %i from file\n"
  862. "\"%s\".\n"
  863. "(this file contains %i lines)\n", iLines, fileName, nLines);
  864. }
  865. /* Read next line */
  866. if (lineLen<=sizeof(localbuf)) {
  867. memcpy(line, localbuf, lineLen);
  868. }
  869. else {
  870. if ( fseek(fp, offset, SEEK_SET != 0) ) {
  871. fclose(fp);
  872. ModelicaFormatError("Error when reading line %i from file\n\"%s\":\n"
  873. "%s\n", iLines, fileName, strerror(errno));
  874. }
  875. nc = ( iLines < nLines ? lineLen+1 : lineLen);
  876. if ( fread(line, sizeof(char), nc, fp) != nc ) {
  877. fclose(fp);
  878. ModelicaFormatError("Error when reading line %i from file\n\"%s\"\n",
  879. iLines, fileName);
  880. }
  881. }
  882. line[lineLen] = '\0';
  883. string[iLines-1] = line;
  884. iLines++;
  885. }
  886. fclose(fp);
  887. }
  888. MODELICA_EXPORT const char* ModelicaInternal_readLine(const char* fileName, int lineNumber, int* endOfFile) {
  889. /* Read line lineNumber from file fileName */
  890. FILE* fp = ModelicaStreams_openFileForReading(fileName, lineNumber - 1);
  891. char* line;
  892. int c, c2;
  893. size_t lineLen;
  894. int offset;
  895. char localbuf[200]; /* To avoid fseek */
  896. if (feof(fp)) {
  897. goto END_OF_FILE;
  898. }
  899. /* Determine length of line lineNumber */
  900. offset = ftell(fp);
  901. lineLen = 0;
  902. c = fgetc(fp);
  903. c2 = c;
  904. while ( c != '\n' && c != EOF ) {
  905. if (lineLen < sizeof(localbuf)) {
  906. localbuf[lineLen] = (char)c;
  907. }
  908. lineLen++;
  909. c2 = c;
  910. c = fgetc(fp);
  911. }
  912. if ( lineLen == 0 && c == EOF ) {
  913. goto END_OF_FILE;
  914. }
  915. /* Read line lineNumber */
  916. if ( lineLen > 0 && c2 == '\r') {
  917. lineLen--;
  918. }
  919. line = ModelicaAllocateStringWithErrorReturn(lineLen);
  920. if ( line == NULL ) {
  921. goto Modelica_ERROR3;
  922. }
  923. if (lineLen <= sizeof(localbuf)) {
  924. memcpy(line, localbuf, lineLen);
  925. }
  926. else {
  927. if ( fseek(fp, offset, SEEK_SET) != 0 ) {
  928. goto Modelica_ERROR3;
  929. }
  930. if ( fread(line, sizeof(char), lineLen, fp) != lineLen ) {
  931. goto Modelica_ERROR3;
  932. }
  933. fgetc(fp); /* Read the EOF/new-line. */
  934. }
  935. CacheFileForReading(fp, fileName, lineNumber);
  936. line[lineLen] = '\0';
  937. *endOfFile = 0;
  938. return line;
  939. /* End-of-File or error */
  940. END_OF_FILE:
  941. fclose(fp);
  942. CloseCachedFile(fileName);
  943. *endOfFile = 1;
  944. line = ModelicaAllocateString(0);
  945. return line;
  946. Modelica_ERROR3:
  947. fclose(fp);
  948. CloseCachedFile(fileName);
  949. ModelicaFormatError("Error when reading line %i from file\n\"%s\":\n%s",
  950. lineNumber, fileName, strerror(errno));
  951. return "";
  952. }
  953. /* --------------------- Modelica_Utilities.System ------------------------------------ */
  954. MODELICA_EXPORT void ModelicaInternal_chdir(const char* directoryName) {
  955. /* Change current working directory */
  956. #if defined(__WATCOMC__) || defined(__LCC__)
  957. int result = chdir(directoryName);
  958. #elif defined(__BORLANDC__)
  959. int result = chdir(directoryName);
  960. #elif defined(_WIN32)
  961. int result = _chdir(directoryName);
  962. #elif defined(_POSIX_) || defined(__GNUC__)
  963. int result = chdir(directoryName);
  964. #else
  965. int result = -1;
  966. ModelicaNotExistError("ModelicaInternal_chdir");
  967. #endif
  968. if (result != 0) {
  969. ModelicaFormatError("Not possible to change current working directory to\n"
  970. "\"%s\":\n%s", directoryName, strerror(errno));
  971. }
  972. }
  973. MODELICA_EXPORT const char* ModelicaInternal_getcwd(int dummy) {
  974. const char* cwd;
  975. char* directory;
  976. #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_POSIX_) || defined(__GNUC__)
  977. char localbuf[BUFFER_LENGTH];
  978. cwd = getcwd(localbuf, sizeof(localbuf));
  979. #elif defined(_WIN32)
  980. char localbuf[BUFFER_LENGTH];
  981. cwd = _getcwd(localbuf, sizeof(localbuf));
  982. #else
  983. ModelicaNotExistError("ModelicaInternal_getcwd");
  984. cwd = "";
  985. #endif
  986. if (cwd == NULL) {
  987. ModelicaFormatError("Not possible to get current working directory:\n%s",
  988. strerror(errno));
  989. cwd = "";
  990. }
  991. directory = ModelicaAllocateString(strlen(cwd));
  992. strcpy(directory, cwd);
  993. ModelicaConvertToUnixDirectorySeparator(directory);
  994. return directory;
  995. }
  996. MODELICA_EXPORT void ModelicaInternal_getenv(const char* name, int convertToSlash, const char** content, int* exist) {
  997. /* Get content of environment variable */
  998. char* result;
  999. #if defined(_MSC_VER) && _MSC_VER >= 1400
  1000. char* value;
  1001. size_t len = 0;
  1002. errno_t err = _dupenv_s(&value, &len, name);
  1003. if (err) {
  1004. value = NULL;
  1005. ModelicaFormatError("Not possible to get environment variable:\n%s", strerror(err));
  1006. }
  1007. #else
  1008. char* value = getenv(name);
  1009. #endif
  1010. #if defined(_MSC_VER) && _MSC_VER >= 1400
  1011. if (value == NULL && len == 0 && err == 0) {
  1012. #else
  1013. if (value == NULL) {
  1014. #endif
  1015. result = ModelicaAllocateString(0);
  1016. result[0] = '\0';
  1017. *exist = 0;
  1018. }
  1019. else {
  1020. #if defined(_MSC_VER) && _MSC_VER >= 1400
  1021. result = ModelicaAllocateStringWithErrorReturn(len); /* (len - 1) actually is sufficient */
  1022. if (result) {
  1023. #else
  1024. result = ModelicaAllocateString(strlen(value));
  1025. #endif
  1026. strcpy(result, value);
  1027. if ( convertToSlash == 1 ) {
  1028. ModelicaConvertToUnixDirectorySeparator(result);
  1029. }
  1030. *exist = 1;
  1031. #if defined(_MSC_VER) && _MSC_VER >= 1400
  1032. free(value);
  1033. }
  1034. else {
  1035. free(value);
  1036. ModelicaFormatError("Not enough memory to allocate string for copying "
  1037. "environment variable \"%s\".\n", name);
  1038. }
  1039. #endif
  1040. }
  1041. *content = result;
  1042. }
  1043. MODELICA_EXPORT void ModelicaInternal_setenv(const char* name, const char* value, int convertFromSlash) {
  1044. #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_WIN32) || defined(_POSIX_) || defined(__GNUC__)
  1045. char localbuf[BUFFER_LENGTH];
  1046. if (strlen(name) + strlen(value) + 1 > sizeof(localbuf)) {
  1047. ModelicaFormatError("Environment variable\n"
  1048. "\"%s\"=\"%s\"\n"
  1049. "cannot be set, because the internal buffer\n"
  1050. "in file \"ModelicaInternal.c\" is too small (= %d)",
  1051. name, value, sizeof(localbuf));
  1052. }
  1053. strcpy(localbuf, name);
  1054. strcat(localbuf, "=");
  1055. strcat(localbuf, value);
  1056. if ( convertFromSlash == 1 ) {
  1057. ModelicaConvertFromUnixDirectorySeparator(&localbuf[strlen(name) + 1]);
  1058. }
  1059. #endif
  1060. /* Set environment variable */
  1061. #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_POSIX_) || defined(__GNUC__)
  1062. if (putenv(localbuf) != 0) {
  1063. ModelicaFormatError("Environment variable\n"
  1064. "\"%s\"=\"%s\"\n"
  1065. "cannot be set: %s", name, value, strerror(errno));
  1066. }
  1067. #elif defined(_WIN32)
  1068. if (_putenv(localbuf) != 0) {
  1069. ModelicaFormatError("Environment variable\n"
  1070. "\"%s\"=\"%s\"\n"
  1071. "cannot be set: %s", name, value, strerror(errno));
  1072. }
  1073. #else
  1074. ModelicaNotExistError("ModelicaInternal_setenv");
  1075. #endif
  1076. }
  1077. #endif
  1078. /* Low-level time and pid functions */
  1079. /* Some parts from: http://nadeausoftware.com/articles/2012/04/c_c_tip_how_measure_elapsed_real_time_benchmarking */
  1080. #if !defined(NO_PID)
  1081. #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_WIN32)
  1082. #include <process.h>
  1083. #elif defined(NO_FILE_SYSTEM) && (defined(_POSIX_) || defined(__GNUC__))
  1084. #include <unistd.h>
  1085. #include <sys/types.h>
  1086. #endif
  1087. #endif
  1088. #if !defined(NO_TIME)
  1089. #include <time.h>
  1090. #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_WIN32)
  1091. #include <sys/timeb.h>
  1092. #elif defined(_POSIX_) || defined(__GNUC__)
  1093. #include <sys/time.h>
  1094. #endif
  1095. #endif
  1096. MODELICA_EXPORT int ModelicaInternal_getpid(void) {
  1097. #if defined(NO_PID)
  1098. return 0;
  1099. #else
  1100. #if defined(_POSIX_) || defined(__GNUC__) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__LCC__)
  1101. return getpid();
  1102. #else
  1103. return _getpid();
  1104. #endif
  1105. #endif
  1106. }
  1107. MODELICA_EXPORT void ModelicaInternal_getTime(int* ms, int* sec, int* min, int* hour, int* mday, int* mon, int* year) {
  1108. #if defined(NO_TIME)
  1109. *ms = 0;
  1110. *sec = 0;
  1111. *min = 0;
  1112. *hour = 0;
  1113. *mday = 0;
  1114. *mon = 0;
  1115. *year = 0;
  1116. #else
  1117. struct tm* tlocal;
  1118. time_t calendarTime;
  1119. int ms0;
  1120. time( &calendarTime ); /* Retrieve sec time */
  1121. tlocal = localtime( &calendarTime ); /* Time fields in local time zone */
  1122. /* Get millisecond resolution depending on platform */
  1123. #if defined(_WIN32)
  1124. {
  1125. #if defined(__BORLANDC__)
  1126. struct timeb timebuffer;
  1127. #else
  1128. struct _timeb timebuffer;
  1129. #endif
  1130. #if defined(__BORLANDC__) || defined(__LCC__)
  1131. ftime( &timebuffer ); /* Retrieve ms time */
  1132. #else
  1133. _ftime( &timebuffer ); /* Retrieve ms time */
  1134. #endif
  1135. ms0 = (int)(timebuffer.millitm); /* Convert unsigned int to int */
  1136. tlocal->tm_mon = tlocal->tm_mon + 1; /* Correct for month starting at 1 */
  1137. tlocal->tm_year = tlocal->tm_year + 1900; /* Correct for 4-digit year */
  1138. }
  1139. #else
  1140. {
  1141. struct timeval tv;
  1142. gettimeofday(&tv, NULL);
  1143. ms0 = tv.tv_usec/1000; /* Convert microseconds to milliseconds */
  1144. }
  1145. #endif
  1146. /* Do not memcpy as you do not know which sizes are in the struct */
  1147. *ms = ms0;
  1148. *sec = tlocal->tm_sec;
  1149. *min = tlocal->tm_min;
  1150. *hour = tlocal->tm_hour;
  1151. *mday = tlocal->tm_mday;
  1152. *mon = tlocal->tm_mon;
  1153. *year = tlocal->tm_year;
  1154. #endif
  1155. }