| author | wenzelm | 
| Fri, 27 Jul 2012 12:43:58 +0200 | |
| changeset 48542 | 0a5f598cacec | 
| parent 48446 | 8f611bc3650b | 
| child 48911 | 5debc3e4fa81 | 
| permissions | -rw-r--r-- | 
| 6118 | 1 | (* Title: Pure/General/file.ML | 
| 5009 | 2 | Author: Markus Wenzel, TU Muenchen | 
| 3 | ||
| 4 | File system operations. | |
| 5 | *) | |
| 6 | ||
| 7 | signature FILE = | |
| 8 | sig | |
| 16261 | 9 | val platform_path: Path.T -> string | 
| 32943 | 10 | val shell_quote: string -> string | 
| 16261 | 11 | val shell_path: Path.T -> string | 
| 6224 | 12 | val cd: Path.T -> unit | 
| 13 | val pwd: unit -> Path.T | |
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 14 | val full_path: Path.T -> Path.T -> Path.T | 
| 6182 | 15 | val tmp_path: Path.T -> Path.T | 
| 17826 | 16 | val exists: Path.T -> bool | 
| 17 | val rm: Path.T -> unit | |
| 40785 | 18 | val is_dir: Path.T -> bool | 
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 19 | val check_dir: Path.T -> Path.T | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 20 | val check_file: Path.T -> Path.T | 
| 43848 | 21 | val open_dir: (OS.FileSys.dirstream -> 'a) -> Path.T -> 'a | 
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 22 | val open_input: (TextIO.instream -> 'a) -> Path.T -> 'a | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 23 | val open_output: (TextIO.outstream -> 'a) -> Path.T -> 'a | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 24 | val open_append: (TextIO.outstream -> 'a) -> Path.T -> 'a | 
| 43848 | 25 | val fold_dir: (string -> 'a -> 'a) -> Path.T -> 'a -> 'a | 
| 26 | val read_dir: Path.T -> string list | |
| 28028 | 27 | 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 | 28 | val fold_pages: (string -> 'a -> 'a) -> Path.T -> 'a -> 'a | 
| 43848 | 29 | val read_lines: Path.T -> string list | 
| 44879 | 30 | val read_pages: Path.T -> string list | 
| 6182 | 31 | val read: Path.T -> string | 
| 32 | val write: Path.T -> string -> unit | |
| 33 | val append: Path.T -> string -> unit | |
| 16713 | 34 | val write_list: Path.T -> string list -> unit | 
| 35 | val append_list: Path.T -> string list -> unit | |
| 28028 | 36 | val write_buffer: Path.T -> Buffer.T -> unit | 
| 16603 | 37 | val eq: Path.T * Path.T -> bool | 
| 6182 | 38 | val copy: Path.T -> Path.T -> unit | 
| 5009 | 39 | end; | 
| 40 | ||
| 41 | structure File: FILE = | |
| 42 | struct | |
| 43 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 44 | (* system path representations *) | 
| 6224 | 45 | |
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 46 | val platform_path = Path.implode o Path.expand; | 
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 47 | |
| 48446 | 48 | val shell_quote = enclose "'" "'"; | 
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 49 | val shell_path = shell_quote o platform_path; | 
| 6224 | 50 | |
| 51 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 52 | (* current working directory *) | 
| 6224 | 53 | |
| 23826 
463903573934
moved cd/pwd to ML compatibility layer (simplifies bootstrapping with Alice);
 wenzelm parents: 
22145diff
changeset | 54 | val cd = cd o platform_path; | 
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 55 | val pwd = Path.explode o pwd; | 
| 6224 | 56 | |
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 57 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 58 | (* full_path *) | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 59 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 60 | fun full_path dir path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 61 | let | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 62 | val path' = Path.expand path; | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 63 | 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 | 64 | val path'' = Path.append dir path'; | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 65 | in | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 66 | if Path.is_absolute path'' then path'' | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 67 | else Path.append (pwd ()) path'' | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 68 | end; | 
| 5009 | 69 | |
| 6182 | 70 | |
| 71 | (* tmp_path *) | |
| 72 | ||
| 73 | fun tmp_path path = | |
| 74 | Path.append (Path.variable "ISABELLE_TMP") (Path.base path); | |
| 5009 | 75 | |
| 76 | ||
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 77 | (* directory entries *) | 
| 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 78 | |
| 23861 
72bb3494746f
replaced info by ident (for full identification, potentially content-based);
 wenzelm parents: 
23826diff
changeset | 79 | val exists = can OS.FileSys.modTime o platform_path; | 
| 16261 | 80 | |
| 81 | val rm = OS.FileSys.remove o platform_path; | |
| 82 | ||
| 40785 | 83 | fun is_dir path = | 
| 84 | the_default false (try OS.FileSys.isDir (platform_path path)); | |
| 85 | ||
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 86 | fun check_dir path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 87 | if exists path andalso is_dir path then path | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 88 |   else error ("No such directory: " ^ Path.print path);
 | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 89 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 90 | fun check_file path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 91 | if exists path andalso not (is_dir path) then path | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 92 |   else error ("No such file: " ^ Path.print path);
 | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 93 | |
| 16261 | 94 | |
| 43848 | 95 | (* open streams *) | 
| 6224 | 96 | |
| 16261 | 97 | local | 
| 98 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 99 | 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 | 100 | let val file = open_file path | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 101 | in Exn.release (Exn.capture f file before close_file file) end; | 
| 6224 | 102 | |
| 16261 | 103 | in | 
| 6218 | 104 | |
| 43848 | 105 | fun open_dir f = with_file OS.FileSys.openDir OS.FileSys.closeDir f o platform_path; | 
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 106 | fun open_input f = with_file TextIO.openIn TextIO.closeIn f o platform_path; | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 107 | fun open_output f = with_file TextIO.openOut TextIO.closeOut f o platform_path; | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 108 | fun open_append f = with_file TextIO.openAppend TextIO.closeOut f o platform_path; | 
| 6224 | 109 | |
| 28028 | 110 | end; | 
| 111 | ||
| 112 | ||
| 43848 | 113 | (* directory content *) | 
| 114 | ||
| 115 | fun fold_dir f path a = open_dir (fn stream => | |
| 116 | let | |
| 117 | fun read x = | |
| 118 | (case OS.FileSys.readDir stream of | |
| 119 | NONE => x | |
| 120 | | SOME entry => read (f entry x)); | |
| 121 | in read a end) path; | |
| 122 | ||
| 123 | fun read_dir path = rev (fold_dir cons path []); | |
| 124 | ||
| 125 | ||
| 28028 | 126 | (* input *) | 
| 127 | ||
| 44879 | 128 | (* | 
| 129 | scalable iterator: | |
| 130 | . avoid size limit of TextIO.inputAll and overhead of many TextIO.inputLine | |
| 131 | . optional terminator at end-of-file | |
| 132 | *) | |
| 43845 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 133 | fun fold_chunks terminator f path a = open_input (fn file => | 
| 28028 | 134 | let | 
| 28510 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 135 | fun read buf x = | 
| 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 136 | (case TextIO.input file of | 
| 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 137 | "" => (case Buffer.content buf of "" => x | line => f line x) | 
| 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 138 | | input => | 
| 43845 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 139 | (case String.fields (fn c => c = terminator) input of | 
| 28510 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 140 | [rest] => read (Buffer.add rest buf) x | 
| 43616 
9e237a9dc1fd
reverted 782991e4180d: fold_fields was never used
 noschinl parents: 
42329diff
changeset | 141 | | 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 | 142 | and read_lines [rest] x = read (Buffer.add rest Buffer.empty) x | 
| 
9e237a9dc1fd
reverted 782991e4180d: fold_fields was never used
 noschinl parents: 
42329diff
changeset | 143 | | read_lines (line :: more) x = read_lines more (f line x); | 
| 28028 | 144 | in read Buffer.empty a end) path; | 
| 145 | ||
| 43845 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 146 | fun fold_lines f = fold_chunks #"\n" f; | 
| 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 147 | fun fold_pages f = fold_chunks #"\f" f; | 
| 
d89353d17f54
added File.fold_pages for streaming of large files;
 wenzelm parents: 
43616diff
changeset | 148 | |
| 43848 | 149 | fun read_lines path = rev (fold_lines cons path []); | 
| 44879 | 150 | fun read_pages path = rev (fold_pages cons path []); | 
| 43848 | 151 | |
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 152 | val read = open_input TextIO.inputAll; | 
| 5009 | 153 | |
| 28028 | 154 | |
| 155 | (* output *) | |
| 156 | ||
| 157 | fun output txts file = List.app (fn txt => TextIO.output (file, txt)) txts; | |
| 158 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 159 | fun write_list path txts = open_output (output txts) path; | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 160 | fun append_list path txts = open_append (output txts) path; | 
| 16713 | 161 | |
| 162 | fun write path txt = write_list path [txt]; | |
| 163 | fun append path txt = append_list path [txt]; | |
| 6182 | 164 | |
| 28028 | 165 | fun write_buffer path buf = open_output (Buffer.output buf) path; | 
| 166 | ||
| 167 | ||
| 168 | (* copy *) | |
| 5009 | 169 | |
| 16603 | 170 | fun eq paths = | 
| 171 | (case try (pairself (OS.FileSys.fileId o platform_path)) paths of | |
| 26656 | 172 | SOME ids => is_equal (OS.FileSys.compare ids) | 
| 16603 | 173 | | NONE => false); | 
| 174 | ||
| 21962 | 175 | fun copy src dst = | 
| 176 | if eq (src, dst) then () | |
| 177 | else | |
| 178 | let val target = if is_dir dst then Path.append dst (Path.base src) else dst | |
| 179 | in write target (read src) end; | |
| 6318 | 180 | |
| 5009 | 181 | end; |