| 1 | within Modelica.Utilities; |
|---|
| 2 | package Files "Functions to work with files and directories" |
|---|
| 3 | function list "List content of file or directory" |
|---|
| 4 | extends Modelica.Icons.Function; |
|---|
| 5 | input String name |
|---|
| 6 | "If name is a directory, list directory content. If it is a file, list the file content"; |
|---|
| 7 | //.............................................................. |
|---|
| 8 | protected |
|---|
| 9 | encapsulated package Local "Local utility functions" |
|---|
| 10 | import Modelica.Utilities.*; |
|---|
| 11 | import Modelica.Utilities.Internal; |
|---|
| 12 | |
|---|
| 13 | function listFile "List content of file" |
|---|
| 14 | input String name; |
|---|
| 15 | protected |
|---|
| 16 | String file[Streams.countLines(name)] = Streams.readFile(name); |
|---|
| 17 | algorithm |
|---|
| 18 | for i in 1:min(size(file,1), 100) loop |
|---|
| 19 | Streams.print(file[i]); |
|---|
| 20 | end for; |
|---|
| 21 | end listFile; |
|---|
| 22 | |
|---|
| 23 | function sortDirectory |
|---|
| 24 | "Sort directory in directories and files with alphabetic order" |
|---|
| 25 | input String directory |
|---|
| 26 | "Directory that was read (including a trailing '/')"; |
|---|
| 27 | input String names[:] |
|---|
| 28 | "File and directory names of a directory in any order"; |
|---|
| 29 | output String orderedNames[size(names,1)] |
|---|
| 30 | "Names of directories followed by names of files"; |
|---|
| 31 | output Integer nDirectories |
|---|
| 32 | "The first nDirectories entries in orderedNames are directories"; |
|---|
| 33 | protected |
|---|
| 34 | Integer nEntries = size(names,1); |
|---|
| 35 | Integer nFiles; |
|---|
| 36 | Integer lenDirectory = Strings.length(directory); |
|---|
| 37 | String directory2; |
|---|
| 38 | algorithm |
|---|
| 39 | // Construct directory with a trailing "/" |
|---|
| 40 | directory2 := if Strings.substring(directory,lenDirectory,lenDirectory) == "/" then |
|---|
| 41 | directory else directory + "/"; |
|---|
| 42 | |
|---|
| 43 | // Distinguish directories and files |
|---|
| 44 | nDirectories := 0; |
|---|
| 45 | nFiles := 0; |
|---|
| 46 | for i in 1:nEntries loop |
|---|
| 47 | if Internal.stat(directory2 + names[i]) == Types.FileType.Directory then |
|---|
| 48 | nDirectories := nDirectories + 1; |
|---|
| 49 | orderedNames[nDirectories] := names[i]; |
|---|
| 50 | else |
|---|
| 51 | nFiles := nFiles + 1; |
|---|
| 52 | orderedNames[nEntries - nFiles + 1] := names[i]; |
|---|
| 53 | end if; |
|---|
| 54 | end for; |
|---|
| 55 | |
|---|
| 56 | // Sort files and directories alphabetically |
|---|
| 57 | if nDirectories > 0 then |
|---|
| 58 | orderedNames[1:nDirectories] := Strings.sort(orderedNames[1:nDirectories], caseSensitive=false); |
|---|
| 59 | end if; |
|---|
| 60 | if nFiles > 0 then |
|---|
| 61 | orderedNames[nDirectories+1:nEntries] := |
|---|
| 62 | Strings.sort(orderedNames[nDirectories+1:nEntries], caseSensitive=false); |
|---|
| 63 | end if; |
|---|
| 64 | end sortDirectory; |
|---|
| 65 | |
|---|
| 66 | function listDirectory "List content of directory" |
|---|
| 67 | input String directoryName; |
|---|
| 68 | input Integer nEntries; |
|---|
| 69 | protected |
|---|
| 70 | String files[nEntries]; |
|---|
| 71 | Integer nDirectories; |
|---|
| 72 | algorithm |
|---|
| 73 | if nEntries > 0 then |
|---|
| 74 | Streams.print("\nDirectory \"" + directoryName + "\":"); |
|---|
| 75 | files := Internal.readDirectory(directoryName, nEntries); |
|---|
| 76 | (files, nDirectories) := sortDirectory(directoryName, files); |
|---|
| 77 | |
|---|
| 78 | // List directories |
|---|
| 79 | if nDirectories > 0 then |
|---|
| 80 | Streams.print(" Subdirectories:"); |
|---|
| 81 | for i in 1:nDirectories loop |
|---|
| 82 | Streams.print(" " + files[i]); |
|---|
| 83 | end for; |
|---|
| 84 | Streams.print(" "); |
|---|
| 85 | end if; |
|---|
| 86 | |
|---|
| 87 | // List files |
|---|
| 88 | if nDirectories < nEntries then |
|---|
| 89 | Streams.print(" Files:"); |
|---|
| 90 | for i in nDirectories+1:nEntries loop |
|---|
| 91 | Streams.print(" " + files[i]); |
|---|
| 92 | end for; |
|---|
| 93 | end if; |
|---|
| 94 | else |
|---|
| 95 | Streams.print("... Directory\"" + directoryName + "\" is empty"); |
|---|
| 96 | end if; |
|---|
| 97 | end listDirectory; |
|---|
| 98 | end Local; |
|---|
| 99 | |
|---|
| 100 | //.............................................................. |
|---|
| 101 | |
|---|
| 102 | Types.FileType.Type fileType; |
|---|
| 103 | algorithm |
|---|
| 104 | fileType := Internal.stat(name); |
|---|
| 105 | if fileType == Types.FileType.RegularFile then |
|---|
| 106 | Local.listFile(name); |
|---|
| 107 | elseif fileType == Types.FileType.Directory then |
|---|
| 108 | Local.listDirectory(name, Internal.getNumberOfFiles(name)); |
|---|
| 109 | elseif fileType == Types.FileType.SpecialFile then |
|---|
| 110 | Streams.error("Cannot list file \"" + name + "\"\n" + |
|---|
| 111 | "since it is not a regular file (pipe, device, ...)"); |
|---|
| 112 | else |
|---|
| 113 | Streams.error("Cannot list file or directory \"" + name + "\"\n" + |
|---|
| 114 | "since it does not exist"); |
|---|
| 115 | end if; |
|---|
| 116 | annotation (preferedView="info",Documentation(info="<html> |
|---|
| 117 | <h4>Syntax</h4> |
|---|
| 118 | <blockquote><pre> |
|---|
| 119 | Files.<b>list</b>(name); |
|---|
| 120 | </pre></blockquote> |
|---|
| 121 | <h4>Description</h4> |
|---|
| 122 | <p> |
|---|
| 123 | If \"name\" is a regular file, the content of the |
|---|
| 124 | file is printed. |
|---|
| 125 | </p> |
|---|
| 126 | <p> |
|---|
| 127 | If \"name\" is a directory, the directory and file names |
|---|
| 128 | in the \"name\" directory are printed in sorted order. |
|---|
| 129 | </p> |
|---|
| 130 | </html>")); |
|---|
| 131 | end list; |
|---|
| 132 | extends Modelica.Icons.Library; |
|---|
| 133 | annotation ( |
|---|
| 134 | version="0.8", |
|---|
| 135 | versionDate="2004-08-24", |
|---|
| 136 | preferedView="info", |
|---|
| 137 | Documentation(info="<HTML> |
|---|
| 138 | <p> |
|---|
| 139 | This package contains functions to work with files and directories. |
|---|
| 140 | As a general convention of this package, '/' is used as directory |
|---|
| 141 | separator both for input and output arguments of all functions. |
|---|
| 142 | For example: |
|---|
| 143 | </p> |
|---|
| 144 | <pre> |
|---|
| 145 | exist(\"Modelica/Mechanics/Rotational.mo\"); |
|---|
| 146 | </pre> |
|---|
| 147 | <p> |
|---|
| 148 | The functions provide the mapping to the directory separator of the |
|---|
| 149 | underlying operating system. Note, that on Windows system the usage |
|---|
| 150 | of '\\' as directory separator would be inconvenient, because this |
|---|
| 151 | character is also the escape character in Modelica and C Strings. |
|---|
| 152 | </p> |
|---|
| 153 | <p> |
|---|
| 154 | In the table below an example call to every function is given: |
|---|
| 155 | </p> |
|---|
| 156 | <table border=1 cellspacing=0 cellpadding=2> |
|---|
| 157 | <tr><th><b><i>Function/type</i></b></th><th><b><i>Description</i></b></th></tr> |
|---|
| 158 | <tr><td valign=\"top\"><a href=\"Modelica://Modelica.Utilities.Files.list\">list</a>(name)</td> |
|---|
| 159 | <td valign=\"top\"> List content of file or of directory.</td> |
|---|
| 160 | </tr> |
|---|
| 161 | <tr><td valign=\"top\"><a href=\"Modelica://Modelica.Utilities.Files.copy\">copy</a>(oldName, newName)<br> |
|---|
| 162 | <a href=\"Modelica://Modelica.Utilities.Files.copy\">copy</a>(oldName, newName, replace=false)</td> |
|---|
| 163 | <td valign=\"top\"> Generate a copy of a file or of a directory.</td> |
|---|
| 164 | </tr> |
|---|
| 165 | <tr><td valign=\"top\"><a href=\"Modelica://Modelica.Utilities.Files.move\">move</a>(oldName, newName)<br> |
|---|
| 166 | <a href=\"Modelica://Modelica.Utilities.Files.move\">move</a>(oldName, newName, replace=false)</td> |
|---|
| 167 | <td valign=\"top\"> Move a file or a directory to another place.</td> |
|---|
| 168 | </tr> |
|---|
| 169 | <tr><td valign=\"top\"><a href=\"Modelica://Modelica.Utilities.Files.remove\">remove</a>(name)</td> |
|---|
| 170 | <td valign=\"top\"> Remove file or directory (ignore call, if it does not exist).</td> |
|---|
| 171 | </tr> |
|---|
| 172 | <tr><td valign=\"top\"><a href=\"Modelica://Modelica.Utilities.Files.removeFile\">removeFile</a>(name)</td> |
|---|
| 173 | <td valign=\"top\"> Remove file (ignore call, if it does not exist)</td> |
|---|
| 174 | </tr> |
|---|
| 175 | <tr><td valign=\"top\"><a href=\"Modelica://Modelica.Utilities.Files.createDirectory\">createDirectory</a>(name)</td> |
|---|
| 176 | <td valign=\"top\"> Create directory (if directory already exists, ignore call).</td> |
|---|
| 177 | </tr> |
|---|
| 178 | <tr><td valign=\"top\">result = <a href=\"Modelica://Modelica.Utilities.Files.exist\">exist</a>(name)</td> |
|---|
| 179 | <td valign=\"top\"> Inquire whether file or directory exists.</td> |
|---|
| 180 | </tr> |
|---|
| 181 | <tr><td valign=\"top\"><a href=\"Modelica://Modelica.Utilities.Files.assertNew\">assertNew</a>(name,message)</td> |
|---|
| 182 | <td valign=\"top\"> Trigger an assert, if a file or directory exists.</td> |
|---|
| 183 | </tr> |
|---|
| 184 | <tr><td valign=\"top\">fullName = <a href=\"Modelica://Modelica.Utilities.Files.fullPathName\">fullPathName</a>(name)</td> |
|---|
| 185 | <td valign=\"top\"> Get full path name of file or directory name.</td> |
|---|
| 186 | </tr> |
|---|
| 187 | <tr><td valign=\"top\">(directory, name, extension) = <a href=\"Modelica://Modelica.Utilities.Files.splitPathName\">splitPathName</a>(name)</td> |
|---|
| 188 | <td valign=\"top\"> Split path name in directory, file name kernel, file name extension.</td> |
|---|
| 189 | </tr> |
|---|
| 190 | <tr><td valign=\"top\">fileName = <a href=\"Modelica://Modelica.Utilities.Files.temporaryFileName\">temporaryFileName</a>()</td> |
|---|
| 191 | <td valign=\"top\"> Return arbitrary name of a file that does not exist<br> |
|---|
| 192 | and is in a directory where access rights allow to <br> |
|---|
| 193 | write to this file (useful for temporary output of files).</td> |
|---|
| 194 | </tr> |
|---|
| 195 | </table> |
|---|
| 196 | </HTML>"), |
|---|
| 197 | Coordsys( |
|---|
| 198 | extent=[0, 0; 417, 614], |
|---|
| 199 | grid=[1, 1], |
|---|
| 200 | component=[20, 20]), |
|---|
| 201 | Window( |
|---|
| 202 | x=0.03, |
|---|
| 203 | y=0.02, |
|---|
| 204 | width=0.42, |
|---|
| 205 | height=0.86, |
|---|
| 206 | library=1, |
|---|
| 207 | autolayout=1)); |
|---|
| 208 | |
|---|
| 209 | function copy "Generate a copy of a file or of a directory" |
|---|
| 210 | extends Modelica.Icons.Function; |
|---|
| 211 | input String oldName "Name of file or directory to be copied"; |
|---|
| 212 | input String newName "Name of copy of the file or of the directory"; |
|---|
| 213 | input Boolean replace=false |
|---|
| 214 | "= true, if an existing file may be replaced by the required copy"; |
|---|
| 215 | //.............................................................. |
|---|
| 216 | protected |
|---|
| 217 | encapsulated function copyDirectory "Copy a directory" |
|---|
| 218 | import Modelica.Utilities.*; |
|---|
| 219 | import Modelica.Utilities.Internal; |
|---|
| 220 | input String oldName |
|---|
| 221 | "Old directory name without trailing '/'; existance is guaranteed"; |
|---|
| 222 | input String newName |
|---|
| 223 | "New diretory name without trailing '/'; directory was already created"; |
|---|
| 224 | input Boolean replace "= true, if an existing newName may be replaced"; |
|---|
| 225 | protected |
|---|
| 226 | Integer nNames = Internal.getNumberOfFiles(oldName); |
|---|
| 227 | String oldNames[nNames]; |
|---|
| 228 | String oldName_i; |
|---|
| 229 | String newName_i; |
|---|
| 230 | algorithm |
|---|
| 231 | oldNames :=Internal.readDirectory(oldName, nNames); |
|---|
| 232 | for i in 1:nNames loop |
|---|
| 233 | oldName_i := oldName + "/" + oldNames[i]; |
|---|
| 234 | newName_i := newName + "/" + oldNames[i]; |
|---|
| 235 | Files.copy(oldName_i, newName_i, replace); |
|---|
| 236 | end for; |
|---|
| 237 | end copyDirectory; |
|---|
| 238 | //.............................................................. |
|---|
| 239 | |
|---|
| 240 | Integer lenOldName = Strings.length(oldName); |
|---|
| 241 | Integer lenNewName = Strings.length(newName); |
|---|
| 242 | String oldName2 = if Strings.substring(oldName,lenOldName,lenOldName) == "/" then |
|---|
| 243 | Strings.substring(oldName,1,lenOldName-1) else oldName; |
|---|
| 244 | String newName2 = if Strings.substring(newName,lenNewName,lenNewName) == "/" then |
|---|
| 245 | Strings.substring(newName,1,lenNewName-1) else newName; |
|---|
| 246 | Types.FileType.Type oldFileType = Internal.stat(oldName2); |
|---|
| 247 | Types.FileType.Type newFileType; |
|---|
| 248 | algorithm |
|---|
| 249 | if oldFileType == Types.FileType.NoFile then |
|---|
| 250 | Streams.error("It is not possible to copy the file or directory\n" + |
|---|
| 251 | "\"" + oldName2 + "\" because it does not exist."); |
|---|
| 252 | elseif oldFileType == Types.FileType.Directory then |
|---|
| 253 | newFileType :=Internal.stat(newName2); |
|---|
| 254 | if newFileType == Types.FileType.NoFile then |
|---|
| 255 | createDirectory(newName2); |
|---|
| 256 | elseif newFileType == Types.FileType.RegularFile or |
|---|
| 257 | newFileType == Types.FileType.SpecialFile then |
|---|
| 258 | if replace then |
|---|
| 259 | Files.removeFile(newName2); |
|---|
| 260 | Files.createDirectory(newName2); |
|---|
| 261 | else |
|---|
| 262 | Streams.error("Directory \"" + oldName2 + "\" should be copied to\n" + |
|---|
| 263 | "\"" + newName2 + "\" which is an existing file.\n" + |
|---|
| 264 | "Since argument replace=false, this is not allowed"); |
|---|
| 265 | end if; |
|---|
| 266 | end if; |
|---|
| 267 | copyDirectory(oldName2, newName2, replace); |
|---|
| 268 | else // regular or special file |
|---|
| 269 | if replace then |
|---|
| 270 | Files.removeFile(newName2); |
|---|
| 271 | else |
|---|
| 272 | Files.assertNew(newName2, "File \"" + oldName2 + "\" should be copied or moved to\n" + |
|---|
| 273 | "\"" + newName2 + "\" which is an existing file or directory.\n" + |
|---|
| 274 | "Since argument replace=false, this is not allowed"); |
|---|
| 275 | end if; |
|---|
| 276 | Internal.copyFile(oldName2, newName2); |
|---|
| 277 | end if; |
|---|
| 278 | annotation (preferedView="info",Documentation(info="<HTML> |
|---|
| 279 | <h4>Syntax</h4> |
|---|
| 280 | <blockquote><pre> |
|---|
| 281 | Files.<b>copy</b>(oldName, newName); |
|---|
| 282 | Files.<b>copy</b>(oldName, newName, replace = true); |
|---|
| 283 | </pre></blockquote> |
|---|
| 284 | <h4>Description</h4> |
|---|
| 285 | <p> |
|---|
| 286 | Function <b>copy</b>(..) copies a file or a directory |
|---|
| 287 | to a new location. Via the optional argument <b>replace</b> |
|---|
| 288 | it can be defined whether an already existing file may |
|---|
| 289 | be replaced by the required copy. |
|---|
| 290 | </p> |
|---|
| 291 | <p> |
|---|
| 292 | If oldName/newName are directories, then the newName |
|---|
| 293 | directory may exist. In such a case the content of oldName |
|---|
| 294 | is copied into directory newName. If replace = <b>false</b> |
|---|
| 295 | it is required that the existing files |
|---|
| 296 | in newName are different from the existing files in |
|---|
| 297 | oldName. |
|---|
| 298 | </p> |
|---|
| 299 | <h4>Example</h4> |
|---|
| 300 | <blockquote><pre> |
|---|
| 301 | copy(\"C:/test1/directory1\", \"C:/test2/directory2\"); |
|---|
| 302 | -> the content of directory1 is copied into directory2 |
|---|
| 303 | if \"C:/test2/directory2\" does not exist, it is newly |
|---|
| 304 | created. If \"replace=true\", files in directory2 |
|---|
| 305 | may be overwritten by their copy |
|---|
| 306 | copy(\"test1.txt\", \"test2.txt\") |
|---|
| 307 | -> make a copy of file \"test1.txt\" with the name \"test2.txt\" |
|---|
| 308 | in the current directory |
|---|
| 309 | </pre></blockquote> |
|---|
| 310 | </HTML>")); |
|---|
| 311 | end copy; |
|---|
| 312 | |
|---|
| 313 | function move "Move a file or a directory to another place" |
|---|
| 314 | extends Modelica.Icons.Function; |
|---|
| 315 | input String oldName "Name of file or directory to be moved"; |
|---|
| 316 | input String newName "New name of the moved file or directory"; |
|---|
| 317 | input Boolean replace=false |
|---|
| 318 | "= true, if an existing file or directory may be replaced"; |
|---|
| 319 | algorithm |
|---|
| 320 | // if both oldName and newName are in the current directory |
|---|
| 321 | // use Internal.renameFile |
|---|
| 322 | if Strings.find(oldName,"/") == 0 and Strings.find(newName,"/") == 0 then |
|---|
| 323 | Internal.rename(oldName, newName); |
|---|
| 324 | else |
|---|
| 325 | Files.copy(oldName, newName, replace); |
|---|
| 326 | Files.remove(oldName); |
|---|
| 327 | end if; |
|---|
| 328 | annotation (preferedView="info",Documentation(info="<HTML> |
|---|
| 329 | <h4>Syntax</h4> |
|---|
| 330 | <blockquote><pre> |
|---|
| 331 | Files.<b>move</b>(oldName, newName); |
|---|
| 332 | Files.<b>move</b>(oldName, newName, replace = true); |
|---|
| 333 | </pre></blockquote> |
|---|
| 334 | <h4>Description</h4> |
|---|
| 335 | <p> |
|---|
| 336 | Function <b>move</b>(..) moves a file or a directory |
|---|
| 337 | to a new location. Via the optional argument <b>replace</b> |
|---|
| 338 | it can be defined whether an already existing file may |
|---|
| 339 | be replaced. |
|---|
| 340 | </p> |
|---|
| 341 | <p> |
|---|
| 342 | If oldName/newName are directories, then the newName |
|---|
| 343 | directory may exist. In such a case the content of oldName |
|---|
| 344 | is moved into directory newName. If replace = <b>false</b> |
|---|
| 345 | it is required that the existing files |
|---|
| 346 | in newName are different from the existing files in |
|---|
| 347 | oldName. |
|---|
| 348 | </p> |
|---|
| 349 | <h4>Example</h4> |
|---|
| 350 | <blockquote><pre> |
|---|
| 351 | move(\"C:/test1/directory1\", \"C:/test2/directory2\"); |
|---|
| 352 | -> the content of directory1 is moved into directory2. |
|---|
| 353 | Afterwards directory1 is deleted. |
|---|
| 354 | if \"C:/test2/directory2\" does not exist, it is newly |
|---|
| 355 | created. If \"replace=true\", files in directory2 |
|---|
| 356 | may be overwritten |
|---|
| 357 | move(\"test1.txt\", \"test2.txt\") |
|---|
| 358 | -> rename file \"test1.txt\" into \"test2.txt\" |
|---|
| 359 | within the current directory |
|---|
| 360 | </pre></blockquote> |
|---|
| 361 | </HTML>")); |
|---|
| 362 | end move; |
|---|
| 363 | |
|---|
| 364 | function remove "Remove file or directory (ignore call, if it does not exist)" |
|---|
| 365 | extends Modelica.Icons.Function; |
|---|
| 366 | input String name "Name of file or directory to be removed"; |
|---|
| 367 | //.............................................................. |
|---|
| 368 | protected |
|---|
| 369 | encapsulated function removeDirectory |
|---|
| 370 | "Remove a directory, even if it is not empty" |
|---|
| 371 | import Modelica.Utilities.*; |
|---|
| 372 | import Modelica.Utilities.Internal; |
|---|
| 373 | input String name; |
|---|
| 374 | protected |
|---|
| 375 | Integer nNames = Internal.getNumberOfFiles(name); |
|---|
| 376 | Integer lenName = Strings.length(name); |
|---|
| 377 | String fileNames[nNames]; |
|---|
| 378 | // remove an optional trailing "/" |
|---|
| 379 | String name2 = if Strings.substring(name,lenName,lenName) == "/" then |
|---|
| 380 | Strings.substring(name,lenName-1,lenName-1) else name; |
|---|
| 381 | algorithm |
|---|
| 382 | fileNames :=Internal.readDirectory(name2, nNames); |
|---|
| 383 | for i in 1:nNames loop |
|---|
| 384 | Files.remove(name2 + "/" + fileNames[i]); |
|---|
| 385 | end for; |
|---|
| 386 | Internal.rmdir(name2); |
|---|
| 387 | end removeDirectory; |
|---|
| 388 | //.............................................................. |
|---|
| 389 | String fullName = Files.fullPathName(name); |
|---|
| 390 | Types.FileType.Type fileType=Internal.stat(fullName); |
|---|
| 391 | algorithm |
|---|
| 392 | if fileType == Types.FileType.RegularFile or |
|---|
| 393 | fileType == Types.FileType.SpecialFile then |
|---|
| 394 | Internal.removeFile(fullName); |
|---|
| 395 | elseif fileType == Types.FileType.Directory then |
|---|
| 396 | removeDirectory(fullName); |
|---|
| 397 | end if; |
|---|
| 398 | annotation (preferedView="info",Documentation(info="<html> |
|---|
| 399 | <h4>Syntax</h4> |
|---|
| 400 | <blockquote><pre> |
|---|
| 401 | Files.<b>remove</b>(name); |
|---|
| 402 | </pre></blockquote> |
|---|
| 403 | <h4>Description</h4> |
|---|
| 404 | <p> |
|---|
| 405 | Removes the file or directory \"name\". If \"name\" does not exist, |
|---|
| 406 | the function call is ignored. If \"name\" is a directory, first |
|---|
| 407 | the content of the directory is removed and afterwards |
|---|
| 408 | the directory itself. |
|---|
| 409 | </p> |
|---|
| 410 | <p> |
|---|
| 411 | This function is silent, i.e., it does not print a message. |
|---|
| 412 | </p> |
|---|
| 413 | </html>")); |
|---|
| 414 | end remove; |
|---|
| 415 | |
|---|
| 416 | function removeFile "Remove file (ignore call, if it does not exist)" |
|---|
| 417 | extends Modelica.Icons.Function; |
|---|
| 418 | input String fileName "Name of file that should be removed"; |
|---|
| 419 | protected |
|---|
| 420 | Types.FileType.Type fileType = Internal.stat(fileName); |
|---|
| 421 | algorithm |
|---|
| 422 | if fileType == Types.FileType.RegularFile then |
|---|
| 423 | Internal.removeFile(fileName); |
|---|
| 424 | elseif fileType == Types.FileType.Directory then |
|---|
| 425 | Streams.error("File \"" + fileName + "\" should be removed.\n" + |
|---|
| 426 | "This is not possible, because it is a directory"); |
|---|
| 427 | elseif fileType == Types.FileType.SpecialFile then |
|---|
| 428 | Streams.error("File \"" + fileName + "\" should be removed.\n" + |
|---|
| 429 | "This is not possible, because it is a special file (pipe, device, etc.)"); |
|---|
| 430 | end if; |
|---|
| 431 | annotation (preferedView="info",Documentation(info="<html> |
|---|
| 432 | <h4>Syntax</h4> |
|---|
| 433 | <blockquote><pre> |
|---|
| 434 | Files.<b>removeFile</b>(fileName); |
|---|
| 435 | </pre></blockquote> |
|---|
| 436 | <h4>Description</h4> |
|---|
| 437 | <p> |
|---|
| 438 | Removes the file \"fileName\". If \"fileName\" does not exist, |
|---|
| 439 | the function call is ignored. If \"fileName\" exists but is |
|---|
| 440 | no regular file (e.g., directory, pipe, device, etc.) an |
|---|
| 441 | error is triggered. |
|---|
| 442 | </p> |
|---|
| 443 | <p> |
|---|
| 444 | This function is silent, i.e., it does not print a message. |
|---|
| 445 | </p> |
|---|
| 446 | </html>")); |
|---|
| 447 | end removeFile; |
|---|
| 448 | |
|---|
| 449 | function createDirectory |
|---|
| 450 | "Create directory (if directory already exists, ignore call)" |
|---|
| 451 | extends Modelica.Icons.Function; |
|---|
| 452 | input String directoryName |
|---|
| 453 | "Name of directory to be created (if present, ignore call)"; |
|---|
| 454 | //.............................................................. |
|---|
| 455 | protected |
|---|
| 456 | encapsulated package Local "Local utility functions" |
|---|
| 457 | import Modelica.Utilities.*; |
|---|
| 458 | import Modelica.Utilities.Internal; |
|---|
| 459 | |
|---|
| 460 | function existDirectory |
|---|
| 461 | "Inquire whether directory exists; if present and not a directory, trigger an error" |
|---|
| 462 | input String directoryName; |
|---|
| 463 | output Boolean exists "true if directory exists"; |
|---|
| 464 | protected |
|---|
| 465 | Types.FileType.Type fileType = Internal.stat(directoryName); |
|---|
| 466 | algorithm |
|---|
| 467 | if fileType == Types.FileType.RegularFile or |
|---|
| 468 | fileType == Types.FileType.SpecialFile then |
|---|
| 469 | Streams.error("Directory \"" + directoryName + "\" cannot be created\n" + |
|---|
| 470 | "because this is an existing file."); |
|---|
| 471 | elseif fileType == Types.FileType.Directory then |
|---|
| 472 | exists :=true; |
|---|
| 473 | else |
|---|
| 474 | exists :=false; |
|---|
| 475 | end if; |
|---|
| 476 | end existDirectory; |
|---|
| 477 | |
|---|
| 478 | function assertCorrectIndex |
|---|
| 479 | "Print error, if index to last essential character in directory is wrong" |
|---|
| 480 | input Integer index "Index must be > 0"; |
|---|
| 481 | input String directoryName "Directory name for error message"; |
|---|
| 482 | algorithm |
|---|
| 483 | if index < 1 then |
|---|
| 484 | Streams.error("It is not possible to create the directory\n" + |
|---|
| 485 | "\"" + directoryName + "\"\n" + |
|---|
| 486 | "because this directory name is not valid"); |
|---|
| 487 | end if; |
|---|
| 488 | end assertCorrectIndex; |
|---|
| 489 | end Local; |
|---|
| 490 | //.............................................................. |
|---|
| 491 | String fullName; |
|---|
| 492 | Integer index; |
|---|
| 493 | Integer oldIndex; |
|---|
| 494 | Integer lastIndex; |
|---|
| 495 | Boolean found; |
|---|
| 496 | Boolean finished; |
|---|
| 497 | Integer nDirectories = 0 "Number of directories that need to be generated"; |
|---|
| 498 | algorithm |
|---|
| 499 | // Ignore call, if directory exists |
|---|
| 500 | if not Local.existDirectory(directoryName) then |
|---|
| 501 | fullName := Files.fullPathName(directoryName); |
|---|
| 502 | |
|---|
| 503 | // Remove a trailing "/" |
|---|
| 504 | index :=Strings.length(fullName); |
|---|
| 505 | if Strings.substring(fullName,index,index) == "/" then |
|---|
| 506 | index :=index - 1; |
|---|
| 507 | Local.assertCorrectIndex(index,fullName); |
|---|
| 508 | end if; |
|---|
| 509 | lastIndex := index; |
|---|
| 510 | fullName := Strings.substring(fullName,1,index); |
|---|
| 511 | |
|---|
| 512 | // Search upper directories until a directory is found that exists |
|---|
| 513 | // ??? check the following while loop later, if also cases such as |
|---|
| 514 | // "c:/", "c:", "//name" are handled correctly ??? |
|---|
| 515 | found := false; |
|---|
| 516 | while not found loop |
|---|
| 517 | oldIndex := index; |
|---|
| 518 | index := Strings.findLast(fullName,"/",startIndex=index); |
|---|
| 519 | if index == 0 then |
|---|
| 520 | index := oldIndex; |
|---|
| 521 | found := true; |
|---|
| 522 | else |
|---|
| 523 | index := index - 1; |
|---|
| 524 | Local.assertCorrectIndex(index, fullName); |
|---|
| 525 | found := Local.existDirectory(Strings.substring(fullName,1,index)); |
|---|
| 526 | end if; |
|---|
| 527 | end while; |
|---|
| 528 | index := oldIndex; |
|---|
| 529 | |
|---|
| 530 | // Create directories |
|---|
| 531 | finished := false; |
|---|
| 532 | while not finished loop |
|---|
| 533 | Internal.mkdir(Strings.substring(fullName,1,index)); |
|---|
| 534 | if index >= lastIndex then |
|---|
| 535 | finished := true; |
|---|
| 536 | elseif index < lastIndex then |
|---|
| 537 | index := Strings.find(fullName, "/", startIndex=index+2); |
|---|
| 538 | if index == 0 then |
|---|
| 539 | index :=lastIndex; |
|---|
| 540 | end if; |
|---|
| 541 | end if; |
|---|
| 542 | end while; |
|---|
| 543 | end if; |
|---|
| 544 | annotation (preferedView="info",Documentation(info="<html> |
|---|
| 545 | <h4>Syntax</h4> |
|---|
| 546 | <blockquote><pre> |
|---|
| 547 | Files.<b>createDirectory</b>(directoryName); |
|---|
| 548 | </pre></blockquote> |
|---|
| 549 | <h4>Description</h4> |
|---|
| 550 | <p> |
|---|
| 551 | Creates directory \"directorName\". If this directory already exists, |
|---|
| 552 | the function call is ignored. If several directories in \"directoryName\" |
|---|
| 553 | do not exist, all of them are created. For example, assume |
|---|
| 554 | that directory \"E:/test1\" exists and that directory |
|---|
| 555 | \"E:/test1/test2/test3\" shall be created. In this case |
|---|
| 556 | the directories \"test2\" in \"test1\" and \"test3\" in \"test2\" |
|---|
| 557 | are created. |
|---|
| 558 | </p> |
|---|
| 559 | <p> |
|---|
| 560 | This function is silent, i.e., it does not print a message. |
|---|
| 561 | In case of error (e.g., \"directoryName\" is an existing regular |
|---|
| 562 | file), an assert is triggered. |
|---|
| 563 | </p> |
|---|
| 564 | </html>")); |
|---|
| 565 | end createDirectory; |
|---|
| 566 | |
|---|
| 567 | function exist "Inquire whether file or directory exists" |
|---|
| 568 | extends Modelica.Icons.Function; |
|---|
| 569 | input String name "Name of file or directory"; |
|---|
| 570 | output Boolean result "= true, if file or directory exists"; |
|---|
| 571 | algorithm |
|---|
| 572 | result := Internal.stat(name) > Types.FileType.NoFile; |
|---|
| 573 | annotation (preferedView="info",Documentation(info="<html> |
|---|
| 574 | <h4>Syntax</h4> |
|---|
| 575 | <blockquote><pre> |
|---|
| 576 | result = Files.<b>exist</b>(name); |
|---|
| 577 | </pre></blockquote> |
|---|
| 578 | <h4>Description</h4> |
|---|
| 579 | <p> |
|---|
| 580 | Returns true, if \"name\" is an existing file or directory. |
|---|
| 581 | If this is not the case, the function returns false. |
|---|
| 582 | </p> |
|---|
| 583 | </html>")); |
|---|
| 584 | end exist; |
|---|
| 585 | |
|---|
| 586 | function assertNew "Trigger an assert, if a file or directory exists" |
|---|
| 587 | extends Modelica.Icons.Function; |
|---|
| 588 | input String name "Name of file or directory"; |
|---|
| 589 | input String message="This is not allowed." |
|---|
| 590 | "Message that should be printed after the default message in a new line"; |
|---|
| 591 | protected |
|---|
| 592 | Types.FileType.Type fileType = Internal.stat(name); |
|---|
| 593 | algorithm |
|---|
| 594 | if fileType == Types.FileType.RegularFile then |
|---|
| 595 | Streams.error("File \"" + name + "\" already exists.\n" + message); |
|---|
| 596 | elseif fileType == Types.FileType.Directory then |
|---|
| 597 | Streams.error("Directory \"" + name + "\" already exists.\n" + message); |
|---|
| 598 | elseif fileType == Types.FileType.SpecialFile then |
|---|
| 599 | Streams.error("A special file (pipe, device, etc.) \"" + name + "\" already exists.\n" + message); |
|---|
| 600 | end if; |
|---|
| 601 | annotation (preferedView="info",Documentation(info="<html> |
|---|
| 602 | <h4>Syntax</h4> |
|---|
| 603 | <blockquote><pre> |
|---|
| 604 | Files.<b>assertNew</b>(name); |
|---|
| 605 | Files.<b>assertNew</b>(name, message=\"This is not allowed\"); |
|---|
| 606 | </pre></blockquote> |
|---|
| 607 | <h4>Description</h4> |
|---|
| 608 | <p> |
|---|
| 609 | Triggers an assert, if \"name\" is an existing file or |
|---|
| 610 | directory. The error message has the following structure: |
|---|
| 611 | </p> |
|---|
| 612 | <pre> |
|---|
| 613 | File \"<name>\" already exists. |
|---|
| 614 | <message> |
|---|
| 615 | </pre> |
|---|
| 616 | </p> |
|---|
| 617 | </html>")); |
|---|
| 618 | end assertNew; |
|---|
| 619 | |
|---|
| 620 | function fullPathName "Get full path name of file or directory name" |
|---|
| 621 | extends Modelica.Icons.Function; |
|---|
| 622 | input String name "Absolute or relative file or directory name"; |
|---|
| 623 | output String fullName "Full path of 'name'"; |
|---|
| 624 | external "C" fullName = ModelicaInternal_fullPathName(name); |
|---|
| 625 | annotation (preferedView="info",Documentation(info="<html> |
|---|
| 626 | <h4>Syntax</h4> |
|---|
| 627 | <blockquote><pre> |
|---|
| 628 | fullName = Files.<b>fullPathName</b>(name); |
|---|
| 629 | </pre></blockquote> |
|---|
| 630 | <h4>Description</h4> |
|---|
| 631 | <p> |
|---|
| 632 | Returns the full path name of a file or directory \"name\". |
|---|
| 633 | </p> |
|---|
| 634 | </html>")); |
|---|
| 635 | end fullPathName; |
|---|
| 636 | |
|---|
| 637 | function splitPathName |
|---|
| 638 | "Split path name in directory, file name kernel, file name extension" |
|---|
| 639 | extends Modelica.Icons.Function; |
|---|
| 640 | input String pathName "Absolute or relative file or directory name"; |
|---|
| 641 | output String directory "Name of the directory including a trailing '/'"; |
|---|
| 642 | output String name "Name of the file without the extension"; |
|---|
| 643 | output String extension "Extension of the file name. Starts with '.'"; |
|---|
| 644 | annotation (preferedView="info",Documentation(info="<HTML> |
|---|
| 645 | <h4>Syntax</h4> |
|---|
| 646 | <blockquote><pre> |
|---|
| 647 | (directory, name, extension) = Files.<b>splitPathName</b>(pathName); |
|---|
| 648 | </pre></blockquote> |
|---|
| 649 | <h4>Description</h4> |
|---|
| 650 | <p> |
|---|
| 651 | Function <b>splitPathName</b>(..) splits a path name into its parts. |
|---|
| 652 | </p> |
|---|
| 653 | <h4>Example</h4> |
|---|
| 654 | <pre> |
|---|
| 655 | (directory, name, extension) = Files.splitPathName(\"C:/user/test/input.txt\") |
|---|
| 656 | |
|---|
| 657 | -> directory = \"C:/user/test/\" |
|---|
| 658 | name = \"input\" |
|---|
| 659 | extension = \".txt\" |
|---|
| 660 | </pre> |
|---|
| 661 | </HTML>")); |
|---|
| 662 | protected |
|---|
| 663 | Integer lenPath = Strings.length(pathName); |
|---|
| 664 | Integer i = lenPath; |
|---|
| 665 | Integer indexDot = 0; |
|---|
| 666 | Integer indexSlash = 0; |
|---|
| 667 | String c; |
|---|
| 668 | algorithm |
|---|
| 669 | while i >= 1 loop |
|---|
| 670 | c :=Strings.substring(pathName, i, i); |
|---|
| 671 | if c == "." then |
|---|
| 672 | indexDot := i; |
|---|
| 673 | i := 0; |
|---|
| 674 | elseif c == "/" then |
|---|
| 675 | indexSlash := i; |
|---|
| 676 | i := 0; |
|---|
| 677 | else |
|---|
| 678 | i := i - 1; |
|---|
| 679 | end if; |
|---|
| 680 | end while; |
|---|
| 681 | |
|---|
| 682 | if indexSlash == lenPath then |
|---|
| 683 | directory := pathName; |
|---|
| 684 | name := ""; |
|---|
| 685 | extension := ""; |
|---|
| 686 | elseif indexDot > 0 then |
|---|
| 687 | indexSlash :=Strings.findLast(pathName, "/", startIndex=indexDot - 1); |
|---|
| 688 | if indexSlash == 0 then |
|---|
| 689 | directory :=""; |
|---|
| 690 | name :=Strings.substring(pathName, 1, indexDot - 1); |
|---|
| 691 | else |
|---|
| 692 | directory :=Strings.substring(pathName, 1, indexSlash); |
|---|
| 693 | name :=Strings.substring(pathName, indexSlash + 1, indexDot - 1); |
|---|
| 694 | end if; |
|---|
| 695 | extension :=Strings.substring(pathName, indexDot, lenPath); |
|---|
| 696 | else |
|---|
| 697 | extension :=""; |
|---|
| 698 | if indexSlash > 0 then |
|---|
| 699 | directory :=Strings.substring(pathName, 1, indexSlash); |
|---|
| 700 | name :=Strings.substring(pathName, indexSlash + 1, lenPath); |
|---|
| 701 | else |
|---|
| 702 | directory :=""; |
|---|
| 703 | name :=pathName; |
|---|
| 704 | end if; |
|---|
| 705 | end if; |
|---|
| 706 | end splitPathName; |
|---|
| 707 | |
|---|
| 708 | function temporaryFileName |
|---|
| 709 | "Return arbitrary name of a file that does not exist and is in a directory where access rights allow to write to this file (useful for temporary output of files)" |
|---|
| 710 | |
|---|