| author | blanchet | 
| Tue, 07 Jun 2011 08:52:35 +0200 | |
| changeset 43228 | 2ed2f092e990 | 
| parent 42329 | 782991e4180d | 
| child 43616 | 9e237a9dc1fd | 
| 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 | 
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 21 | 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 | 22 | 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 | 23 | val open_append: (TextIO.outstream -> 'a) -> Path.T -> 'a | 
| 42329 | 24 | val fold_fields: (char -> bool) -> (string -> 'a -> 'a) -> Path.T -> 'a -> 'a | 
| 28028 | 25 | val fold_lines: (string -> 'a -> 'a) -> Path.T -> 'a -> 'a | 
| 6182 | 26 | val read: Path.T -> string | 
| 27 | val write: Path.T -> string -> unit | |
| 28 | val append: Path.T -> string -> unit | |
| 16713 | 29 | val write_list: Path.T -> string list -> unit | 
| 30 | val append_list: Path.T -> string list -> unit | |
| 28028 | 31 | val write_buffer: Path.T -> Buffer.T -> unit | 
| 16603 | 32 | val eq: Path.T * Path.T -> bool | 
| 6182 | 33 | val copy: Path.T -> Path.T -> unit | 
| 5009 | 34 | end; | 
| 35 | ||
| 36 | structure File: FILE = | |
| 37 | struct | |
| 38 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 39 | (* system path representations *) | 
| 6224 | 40 | |
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 41 | val platform_path = Path.implode o Path.expand; | 
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 42 | |
| 40746 | 43 | fun shell_quote s = | 
| 44 | if exists_string (fn c => c = "'") s then | |
| 45 |     error ("Illegal single quote in path specification: " ^ quote s)
 | |
| 46 | else enclose "'" "'" s; | |
| 47 | ||
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 48 | val shell_path = shell_quote o platform_path; | 
| 6224 | 49 | |
| 50 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 51 | (* current working directory *) | 
| 6224 | 52 | |
| 23826 
463903573934
moved cd/pwd to ML compatibility layer (simplifies bootstrapping with Alice);
 wenzelm parents: 
22145diff
changeset | 53 | 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 | 54 | val pwd = Path.explode o pwd; | 
| 6224 | 55 | |
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 56 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 57 | (* full_path *) | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 58 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 59 | fun full_path dir path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 60 | let | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 61 | val path' = Path.expand path; | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 62 | 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 | 63 | val path'' = Path.append dir path'; | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 64 | in | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 65 | if Path.is_absolute path'' then path'' | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 66 | else Path.append (pwd ()) path'' | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 67 | end; | 
| 5009 | 68 | |
| 6182 | 69 | |
| 70 | (* tmp_path *) | |
| 71 | ||
| 72 | fun tmp_path path = | |
| 73 | Path.append (Path.variable "ISABELLE_TMP") (Path.base path); | |
| 5009 | 74 | |
| 75 | ||
| 26980 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 76 | (* directory entries *) | 
| 
f7f48bb9a025
ident: naive caching prevents potentially slow external invocations;
 wenzelm parents: 
26946diff
changeset | 77 | |
| 23861 
72bb3494746f
replaced info by ident (for full identification, potentially content-based);
 wenzelm parents: 
23826diff
changeset | 78 | val exists = can OS.FileSys.modTime o platform_path; | 
| 16261 | 79 | |
| 80 | val rm = OS.FileSys.remove o platform_path; | |
| 81 | ||
| 40785 | 82 | fun is_dir path = | 
| 83 | the_default false (try OS.FileSys.isDir (platform_path path)); | |
| 84 | ||
| 42003 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 85 | fun check_dir path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 86 | 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 | 87 |   else error ("No such directory: " ^ Path.print path);
 | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 88 | |
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 89 | fun check_file path = | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 90 | 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 | 91 |   else error ("No such file: " ^ Path.print path);
 | 
| 
6e45dc518ebb
replaced File.check by specific File.check_file, File.check_dir;
 wenzelm parents: 
41944diff
changeset | 92 | |
| 16261 | 93 | |
| 28028 | 94 | (* open files *) | 
| 6224 | 95 | |
| 16261 | 96 | local | 
| 97 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 98 | 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 | 99 | let val file = open_file path | 
| 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 100 | in Exn.release (Exn.capture f file before close_file file) end; | 
| 6224 | 101 | |
| 16261 | 102 | in | 
| 6218 | 103 | |
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 104 | 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 | 105 | 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 | 106 | fun open_append f = with_file TextIO.openAppend TextIO.closeOut f o platform_path; | 
| 6224 | 107 | |
| 28028 | 108 | end; | 
| 109 | ||
| 110 | ||
| 111 | (* input *) | |
| 112 | ||
| 113 | (*scalable iterator -- avoid size limit of TextIO.inputAll, and overhead of many TextIO.inputLine*) | |
| 42329 | 114 | fun fold_fields sep f path a = open_input (fn file => | 
| 28028 | 115 | let | 
| 28510 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 116 | fun read buf x = | 
| 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 117 | (case TextIO.input file of | 
| 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 118 | "" => (case Buffer.content buf of "" => x | line => f line x) | 
| 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 119 | | input => | 
| 42329 | 120 | (case String.fields sep input of | 
| 28510 
66b95e857bde
fold_lines: more tuning, avoiding extra split_last;
 wenzelm parents: 
28500diff
changeset | 121 | [rest] => read (Buffer.add rest buf) x | 
| 42329 | 122 | | field :: more => read_fields more (f (Buffer.content (Buffer.add field buf)) x))) | 
| 123 | and read_fields [rest] x = read (Buffer.add rest Buffer.empty) x | |
| 124 | | read_fields (field :: more) x = read_fields more (f field x); | |
| 28028 | 125 | in read Buffer.empty a end) path; | 
| 126 | ||
| 42329 | 127 | fun fold_lines f path a = fold_fields (fn c => c = #"\n") f path a; | 
| 128 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 129 | val read = open_input TextIO.inputAll; | 
| 5009 | 130 | |
| 28028 | 131 | |
| 132 | (* output *) | |
| 133 | ||
| 134 | fun output txts file = List.app (fn txt => TextIO.output (file, txt)) txts; | |
| 135 | ||
| 26503 
4dec4460244f
discontinued unused hooks explode_platform_path_fn, platform_path_fn, shell_path_fn;
 wenzelm parents: 
26220diff
changeset | 136 | 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 | 137 | fun append_list path txts = open_append (output txts) path; | 
| 16713 | 138 | |
| 139 | fun write path txt = write_list path [txt]; | |
| 140 | fun append path txt = append_list path [txt]; | |
| 6182 | 141 | |
| 28028 | 142 | fun write_buffer path buf = open_output (Buffer.output buf) path; | 
| 143 | ||
| 144 | ||
| 145 | (* copy *) | |
| 5009 | 146 | |
| 16603 | 147 | fun eq paths = | 
| 148 | (case try (pairself (OS.FileSys.fileId o platform_path)) paths of | |
| 26656 | 149 | SOME ids => is_equal (OS.FileSys.compare ids) | 
| 16603 | 150 | | NONE => false); | 
| 151 | ||
| 21962 | 152 | fun copy src dst = | 
| 153 | if eq (src, dst) then () | |
| 154 | else | |
| 155 | let val target = if is_dir dst then Path.append dst (Path.base src) else dst | |
| 156 | in write target (read src) end; | |
| 6318 | 157 | |
| 5009 | 158 | end; |