| author | wenzelm | 
| Mon, 28 Aug 2017 20:15:11 +0200 | |
| changeset 66530 | a3a847c4fbdb | 
| parent 64698 | e022a69db531 | 
| child 69223 | 44d68a00917c | 
| permissions | -rw-r--r-- | 
| 6118 | 1 | (* Title: Pure/General/file.ML | 
| 64698 | 2 | Author: Makarius | 
| 5009 | 3 | |
| 64698 | 4 | File-system operations. | 
| 5009 | 5 | *) | 
| 6 | ||
| 7 | signature FILE = | |
| 8 | sig | |
| 60970 
e08d868ceca9
clarified File.standard_path vs. File.platform_path (like Isabelle/Scala operations);
 wenzelm parents: 
59058diff
changeset | 9 | val standard_path: Path.T -> string | 
| 16261 | 10 | val platform_path: Path.T -> string | 
| 62549 
9498623b27f0
File.bash_string operations in ML as in Scala -- exclusively for GNU bash, not perl and not user output;
 wenzelm parents: 
62468diff
changeset | 11 | val bash_path: Path.T -> string | 
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 12 | val full_path: Path.T -> Path.T -> Path.T | 
| 6182 | 13 | val tmp_path: Path.T -> Path.T | 
| 17826 | 14 | val exists: Path.T -> bool | 
| 15 | val rm: Path.T -> unit | |
| 40785 | 16 | val is_dir: Path.T -> bool | 
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 17 | val check_dir: Path.T -> Path.T | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 18 | val check_file: Path.T -> Path.T | 
| 43848 | 19 | val open_dir: (OS.FileSys.dirstream -> 'a) -> Path.T -> 'a | 
| 60982 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 20 | val open_input: (BinIO.instream -> 'a) -> Path.T -> 'a | 
| 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 21 | val open_output: (BinIO.outstream -> 'a) -> Path.T -> 'a | 
| 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 22 | val open_append: (BinIO.outstream -> 'a) -> Path.T -> 'a | 
| 43848 | 23 | val fold_dir: (string -> 'a -> 'a) -> Path.T -> 'a -> 'a | 
| 24 | val read_dir: Path.T -> string list | |
| 28028 | 25 | val fold_lines: (string -> 'a -> 'a) -> Path.T -> 'a -> 'a | 
| 43845 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 26 | val fold_pages: (string -> 'a -> 'a) -> Path.T -> 'a -> 'a | 
| 43848 | 27 | val read_lines: Path.T -> string list | 
| 44879 | 28 | val read_pages: Path.T -> string list | 
| 6182 | 29 | val read: Path.T -> string | 
| 30 | val write: Path.T -> string -> unit | |
| 31 | val append: Path.T -> string -> unit | |
| 60982 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 32 | val output: BinIO.outstream -> string -> unit | 
| 16713 | 33 | val write_list: Path.T -> string list -> unit | 
| 34 | val append_list: Path.T -> string list -> unit | |
| 28028 | 35 | val write_buffer: Path.T -> Buffer.T -> unit | 
| 16603 | 36 | val eq: Path.T * Path.T -> bool | 
| 5009 | 37 | end; | 
| 38 | ||
| 39 | structure File: FILE = | |
| 40 | struct | |
| 41 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 42 | (* system path representations *) | 
| 6224 | 43 | |
| 60970 
e08d868ceca9
clarified File.standard_path vs. File.platform_path (like Isabelle/Scala operations);
 wenzelm parents: 
59058diff
changeset | 44 | val standard_path = Path.implode o Path.expand; | 
| 62468 | 45 | val platform_path = ML_System.platform_path o standard_path; | 
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 46 | |
| 64304 | 47 | val bash_path = Bash_Syntax.string o standard_path; | 
| 6224 | 48 | |
| 49 | ||
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 50 | (* full_path *) | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 51 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 52 | fun full_path dir path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 53 | let | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 54 | val path' = Path.expand path; | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 55 | val _ = Path.is_current path' andalso error "Bad file specification"; | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 56 | val path'' = Path.append dir path'; | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 57 | in | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 58 | if Path.is_absolute path'' then path'' | 
| 62551 | 59 | else Path.append (Path.explode (ML_System.standard_path (OS.FileSys.getDir ()))) path'' | 
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 60 | end; | 
| 5009 | 61 | |
| 6182 | 62 | |
| 63 | (* tmp_path *) | |
| 64 | ||
| 65 | fun tmp_path path = | |
| 66 | Path.append (Path.variable "ISABELLE_TMP") (Path.base path); | |
| 5009 | 67 | |
| 68 | ||
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 69 | (* directory entries *) | 
| 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 70 | |
| 23861 
72bb3494746f
replaced info by ident (for full identification, potentially content-based);
 wenzelm parents: 
23826diff
changeset | 71 | val exists = can OS.FileSys.modTime o platform_path; | 
| 16261 | 72 | |
| 73 | val rm = OS.FileSys.remove o platform_path; | |
| 74 | ||
| 40785 | 75 | fun is_dir path = | 
| 76 | the_default false (try OS.FileSys.isDir (platform_path path)); | |
| 77 | ||
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 78 | fun check_dir path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 79 | if exists path andalso is_dir path then path | 
| 63668 | 80 |   else error ("No such directory: " ^ Path.print (Path.expand path));
 | 
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 81 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 82 | fun check_file path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 83 | if exists path andalso not (is_dir path) then path | 
| 63668 | 84 |   else error ("No such file: " ^ Path.print (Path.expand path));
 | 
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 85 | |
| 16261 | 86 | |
| 43848 | 87 | (* open streams *) | 
| 6224 | 88 | |
| 16261 | 89 | local | 
| 90 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 91 | fun with_file open_file close_file f path = | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 92 | let val file = open_file path | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 93 | in Exn.release (Exn.capture f file before close_file file) end; | 
| 6224 | 94 | |
| 16261 | 95 | in | 
| 6218 | 96 | |
| 43848 | 97 | fun open_dir f = with_file OS.FileSys.openDir OS.FileSys.closeDir f o platform_path; | 
| 60982 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 98 | fun open_input f = with_file BinIO.openIn BinIO.closeIn f o platform_path; | 
| 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 99 | fun open_output f = with_file BinIO.openOut BinIO.closeOut f o platform_path; | 
| 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 100 | fun open_append f = with_file BinIO.openAppend BinIO.closeOut f o platform_path; | 
| 6224 | 101 | |
| 28028 | 102 | end; | 
| 103 | ||
| 104 | ||
| 43848 | 105 | (* directory content *) | 
| 106 | ||
| 107 | fun fold_dir f path a = open_dir (fn stream => | |
| 108 | let | |
| 109 | fun read x = | |
| 110 | (case OS.FileSys.readDir stream of | |
| 111 | NONE => x | |
| 112 | | SOME entry => read (f entry x)); | |
| 113 | in read a end) path; | |
| 114 | ||
| 115 | fun read_dir path = rev (fold_dir cons path []); | |
| 116 | ||
| 117 | ||
| 28028 | 118 | (* input *) | 
| 119 | ||
| 44879 | 120 | (* | 
| 121 | scalable iterator: | |
| 122 | . avoid size limit of TextIO.inputAll and overhead of many TextIO.inputLine | |
| 48911 
5debc3e4fa81
tuned messages: end-of-input rarely means physical end-of-file from the past;
 wenzelm parents: 
48446diff
changeset | 123 | . optional terminator at end-of-input | 
| 44879 | 124 | *) | 
| 43845 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 125 | fun fold_chunks terminator f path a = open_input (fn file => | 
| 28028 | 126 | let | 
| 28510 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 127 | fun read buf x = | 
| 60982 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 128 | (case Byte.bytesToString (BinIO.input file) of | 
| 28510 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 129 | "" => (case Buffer.content buf of "" => x | line => f line x) | 
| 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 130 | | input => | 
| 43845 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 131 | (case String.fields (fn c => c = terminator) input of | 
| 28510 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 132 | [rest] => read (Buffer.add rest buf) x | 
| 43616 
9e237a9dc1fd
reverted 782991e4180d: fold_fields was never used
 noschinl parents: 
42329diff
changeset | 133 | | line :: more => read_lines more (f (Buffer.content (Buffer.add line buf)) x))) | 
| 
9e237a9dc1fd
reverted 782991e4180d: fold_fields was never used
 noschinl parents: 
42329diff
changeset | 134 | and read_lines [rest] x = read (Buffer.add rest Buffer.empty) x | 
| 
9e237a9dc1fd
reverted 782991e4180d: fold_fields was never used
 noschinl parents: 
42329diff
changeset | 135 | | read_lines (line :: more) x = read_lines more (f line x); | 
| 28028 | 136 | in read Buffer.empty a end) path; | 
| 137 | ||
| 43845 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 138 | fun fold_lines f = fold_chunks #"\n" f; | 
| 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 139 | fun fold_pages f = fold_chunks #"\f" f; | 
| 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 140 | |
| 43848 | 141 | fun read_lines path = rev (fold_lines cons path []); | 
| 44879 | 142 | fun read_pages path = rev (fold_pages cons path []); | 
| 43848 | 143 | |
| 60982 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 144 | val read = open_input (Byte.bytesToString o BinIO.inputAll); | 
| 5009 | 145 | |
| 28028 | 146 | |
| 147 | (* output *) | |
| 148 | ||
| 60982 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 149 | fun output file txt = BinIO.output (file, Byte.stringToBytes txt); | 
| 28028 | 150 | |
| 60982 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 151 | fun output_list txts file = List.app (output file) txts; | 
| 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 152 | fun write_list path txts = open_output (output_list txts) path; | 
| 
67e389f67073
precise BinIO, without newline conversion on Windows;
 wenzelm parents: 
60970diff
changeset | 153 | fun append_list path txts = open_append (output_list txts) path; | 
| 16713 | 154 | |
| 155 | fun write path txt = write_list path [txt]; | |
| 156 | fun append path txt = append_list path [txt]; | |
| 6182 | 157 | |
| 28028 | 158 | fun write_buffer path buf = open_output (Buffer.output buf) path; | 
| 159 | ||
| 160 | ||
| 56533 
cd8b6d849b6a
explicit 'document_files' in session ROOT specifications;
 wenzelm parents: 
48911diff
changeset | 161 | (* eq *) | 
| 5009 | 162 | |
| 16603 | 163 | fun eq paths = | 
| 59058 
a78612c67ec0
renamed "pairself" to "apply2", in accordance to @{apply 2};
 wenzelm parents: 
56533diff
changeset | 164 | (case try (apply2 (OS.FileSys.fileId o platform_path)) paths of | 
| 26656 | 165 | SOME ids => is_equal (OS.FileSys.compare ids) | 
| 16603 | 166 | | NONE => false); | 
| 167 | ||
| 5009 | 168 | end; |