Mercurial > octave
comparison liboctave/system/lo-sysdep.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 597f3ee61a48 |
comparison
equal
deleted
inserted
replaced
31605:e88a07dec498 | 31607:aac27ad79be6 |
---|---|
53 | 53 |
54 OCTAVE_BEGIN_NAMESPACE(octave) | 54 OCTAVE_BEGIN_NAMESPACE(octave) |
55 | 55 |
56 OCTAVE_BEGIN_NAMESPACE(sys) | 56 OCTAVE_BEGIN_NAMESPACE(sys) |
57 | 57 |
58 int | 58 int |
59 system (const std::string& cmd_str) | 59 system (const std::string& cmd_str) |
60 { | 60 { |
61 #if defined (OCTAVE_USE_WINDOWS_API) | 61 #if defined (OCTAVE_USE_WINDOWS_API) |
62 const std::wstring wcmd_str = u8_to_wstring (cmd_str); | 62 const std::wstring wcmd_str = u8_to_wstring (cmd_str); |
63 | 63 |
64 return _wsystem (wcmd_str.c_str ()); | 64 return _wsystem (wcmd_str.c_str ()); |
65 #else | 65 #else |
66 return ::system (cmd_str.c_str ()); | 66 return ::system (cmd_str.c_str ()); |
67 #endif | 67 #endif |
68 } | 68 } |
69 | 69 |
70 std::string | 70 std::string |
71 getcwd (void) | 71 getcwd (void) |
72 { | 72 { |
73 std::string retval; | 73 std::string retval; |
74 | 74 |
75 #if defined (OCTAVE_USE_WINDOWS_API) | 75 #if defined (OCTAVE_USE_WINDOWS_API) |
76 wchar_t *tmp = _wgetcwd (nullptr, 0); | 76 wchar_t *tmp = _wgetcwd (nullptr, 0); |
77 | 77 |
78 if (! tmp) | 78 if (! tmp) |
79 (*current_liboctave_error_handler) ("unable to find current directory"); | 79 (*current_liboctave_error_handler) ("unable to find current directory"); |
80 | 80 |
81 std::wstring tmp_wstr (tmp); | 81 std::wstring tmp_wstr (tmp); |
82 free (tmp); | 82 free (tmp); |
83 | 83 |
84 std::string tmp_str = u8_from_wstring (tmp_wstr); | 84 std::string tmp_str = u8_from_wstring (tmp_wstr); |
85 | 85 |
86 retval = tmp_str; | 86 retval = tmp_str; |
87 | 87 |
88 #else | 88 #else |
89 // Using octave_getcwd_wrapper ensures that we have a getcwd that | 89 // Using octave_getcwd_wrapper ensures that we have a getcwd that |
90 // will allocate a buffer as large as necessary if buf and size are | 90 // will allocate a buffer as large as necessary if buf and size are |
91 // both 0. | 91 // both 0. |
92 | 92 |
93 char *tmp = octave_getcwd_wrapper (nullptr, 0); | 93 char *tmp = octave_getcwd_wrapper (nullptr, 0); |
94 | 94 |
95 if (! tmp) | 95 if (! tmp) |
96 (*current_liboctave_error_handler) ("unable to find current directory"); | 96 (*current_liboctave_error_handler) ("unable to find current directory"); |
97 | 97 |
98 retval = tmp; | 98 retval = tmp; |
99 free (tmp); | 99 free (tmp); |
100 #endif | 100 #endif |
101 | 101 |
102 return retval; | 102 return retval; |
103 } | 103 } |
104 | 104 |
105 int | 105 int |
106 chdir (const std::string& path_arg) | 106 chdir (const std::string& path_arg) |
107 { | 107 { |
108 std::string path = sys::file_ops::tilde_expand (path_arg); | 108 std::string path = sys::file_ops::tilde_expand (path_arg); |
109 | 109 |
110 #if defined (OCTAVE_USE_WINDOWS_API) | 110 #if defined (OCTAVE_USE_WINDOWS_API) |
111 if (path.length () == 2 && path[1] == ':') | 111 if (path.length () == 2 && path[1] == ':') |
112 path += '\\'; | 112 path += '\\'; |
113 #endif | 113 #endif |
114 | 114 |
115 return octave_chdir_wrapper (path.c_str ()); | 115 return octave_chdir_wrapper (path.c_str ()); |
116 } | 116 } |
117 | 117 |
118 bool | 118 bool |
119 get_dirlist (const std::string& dirname, string_vector& dirlist, | 119 get_dirlist (const std::string& dirname, string_vector& dirlist, |
120 std::string& msg) | 120 std::string& msg) |
121 { | 121 { |
122 dirlist = ""; | 122 dirlist = ""; |
123 msg = ""; | 123 msg = ""; |
124 #if defined (OCTAVE_USE_WINDOWS_API) | 124 #if defined (OCTAVE_USE_WINDOWS_API) |
125 _WIN32_FIND_DATAW ffd; | 125 _WIN32_FIND_DATAW ffd; |
126 | 126 |
127 std::string path_name (dirname); | 127 std::string path_name (dirname); |
128 if (path_name.empty ()) | 128 if (path_name.empty ()) |
129 return true; | 129 return true; |
130 | 130 |
131 if (path_name.back () == '\\' || path_name.back () == '/') | 131 if (path_name.back () == '\\' || path_name.back () == '/') |
132 path_name.push_back ('*'); | 132 path_name.push_back ('*'); |
133 else | 133 else |
134 path_name.append (R"(\*)"); | 134 path_name.append (R"(\*)"); |
135 | 135 |
136 // Find first file in directory. | 136 // Find first file in directory. |
137 std::wstring wpath_name = u8_to_wstring (path_name); | 137 std::wstring wpath_name = u8_to_wstring (path_name); |
138 HANDLE hFind = FindFirstFileW (wpath_name.c_str (), &ffd); | 138 HANDLE hFind = FindFirstFileW (wpath_name.c_str (), &ffd); |
139 if (INVALID_HANDLE_VALUE == hFind) | 139 if (INVALID_HANDLE_VALUE == hFind) |
140 { | |
141 DWORD errCode = GetLastError (); | |
142 char *errorText = nullptr; | |
143 FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM | | |
144 FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
145 FORMAT_MESSAGE_IGNORE_INSERTS, | |
146 nullptr, errCode, | |
147 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), | |
148 reinterpret_cast <char *> (&errorText), 0, nullptr); | |
149 if (errorText != nullptr) | |
140 { | 150 { |
141 DWORD errCode = GetLastError (); | 151 msg = std::string (errorText); |
142 char *errorText = nullptr; | 152 LocalFree (errorText); |
143 FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM | | 153 } |
144 FORMAT_MESSAGE_ALLOCATE_BUFFER | | 154 return false; |
145 FORMAT_MESSAGE_IGNORE_INSERTS, | 155 } |
146 nullptr, errCode, | 156 |
147 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), | 157 std::list<std::string> dirlist_str; |
148 reinterpret_cast <char *> (&errorText), 0, nullptr); | 158 do |
149 if (errorText != nullptr) | 159 dirlist_str.push_back (u8_from_wstring (ffd.cFileName)); |
150 { | 160 while (FindNextFileW (hFind, &ffd) != 0); |
151 msg = std::string (errorText); | 161 |
152 LocalFree (errorText); | 162 FindClose(hFind); |
153 } | 163 |
164 dirlist = string_vector (dirlist_str); | |
165 | |
166 #else | |
167 | |
168 dir_entry dir (dirname); | |
169 | |
170 if (! dir) | |
171 { | |
172 msg = dir.error (); | |
173 return false; | |
174 } | |
175 | |
176 dirlist = dir.read (); | |
177 | |
178 dir.close (); | |
179 #endif | |
180 | |
181 return true; | |
182 } | |
183 | |
184 #if defined (OCTAVE_USE_WINDOWS_API) | |
185 | |
186 static bool check_fseek_ftell_workaround_needed (bool set_nonbuffered_mode) | |
187 { | |
188 // To check whether the workaround is needed: | |
189 // | |
190 // * Create a tmp file with LF line endings only. | |
191 // | |
192 // * Open that file for reading in text mode. | |
193 // | |
194 // * Read a line. | |
195 // | |
196 // * Use ftello to record the position of the beginning of the | |
197 // second line. | |
198 // | |
199 // * Read and save the contents of the second line. | |
200 // | |
201 // * Use fseeko to return to the saved position. | |
202 // | |
203 // * Read the second line again and compare to the previously | |
204 // saved text. | |
205 // | |
206 // * If the lines are different, we need to set non-buffered | |
207 // input mode for files opened in text mode. | |
208 | |
209 std::string tmpname = sys::tempnam ("", "oct-"); | |
210 | |
211 if (tmpname.empty ()) | |
212 { | |
213 (*current_liboctave_warning_handler) | |
214 ("fseek/ftell bug check failed (tmp name creation)!"); | |
215 return false; | |
216 } | |
217 | |
218 std::FILE *fptr = std::fopen (tmpname.c_str (), "wb"); | |
219 | |
220 if (! fptr) | |
221 { | |
222 (*current_liboctave_warning_handler) | |
223 ("fseek/ftell bug check failed (opening tmp file for writing)!"); | |
224 return false; | |
225 } | |
226 | |
227 fprintf (fptr, "%s", "foo\nbar\nbaz\n"); | |
228 | |
229 std::fclose (fptr); | |
230 | |
231 fptr = std::fopen (tmpname.c_str (), "rt"); | |
232 | |
233 if (! fptr) | |
234 { | |
235 (*current_liboctave_warning_handler) | |
236 ("fseek/ftell bug check failed (opening tmp file for reading)!"); | |
237 return false; | |
238 } | |
239 | |
240 unwind_action act ([=] () | |
241 { | |
242 std::fclose (fptr); | |
243 sys::unlink (tmpname); | |
244 }); | |
245 | |
246 if (set_nonbuffered_mode) | |
247 ::setvbuf (fptr, nullptr, _IONBF, 0); | |
248 | |
249 while (true) | |
250 { | |
251 int c = fgetc (fptr); | |
252 | |
253 if (c == EOF) | |
254 { | |
255 (*current_liboctave_warning_handler) | |
256 ("fseek/ftell bug check failed (skipping first line)!"); | |
154 return false; | 257 return false; |
155 } | 258 } |
156 | 259 |
157 std::list<std::string> dirlist_str; | 260 if (c == '\n') |
158 do | 261 break; |
159 dirlist_str.push_back (u8_from_wstring (ffd.cFileName)); | 262 } |
160 while (FindNextFileW (hFind, &ffd) != 0); | 263 |
161 | 264 off_t pos = octave_ftello_wrapper (fptr); |
162 FindClose(hFind); | 265 |
163 | 266 char buf1[8]; |
164 dirlist = string_vector (dirlist_str); | 267 int i = 0; |
165 | 268 while (true) |
166 #else | 269 { |
167 | 270 int c = fgetc (fptr); |
168 dir_entry dir (dirname); | 271 |
169 | 272 if (c == EOF) |
170 if (! dir) | |
171 { | 273 { |
172 msg = dir.error (); | 274 (*current_liboctave_warning_handler) |
275 ("fseek/ftell bug check failed (reading second line)!"); | |
173 return false; | 276 return false; |
174 } | 277 } |
175 | 278 |
176 dirlist = dir.read (); | 279 if (c == '\n') |
177 | 280 break; |
178 dir.close (); | 281 |
179 #endif | 282 buf1[i++] = static_cast<char> (c); |
180 | 283 } |
181 return true; | 284 buf1[i] = '\0'; |
182 } | 285 |
183 | 286 octave_fseeko_wrapper (fptr, pos, SEEK_SET); |
184 #if defined (OCTAVE_USE_WINDOWS_API) | 287 |
185 | 288 char buf2[8]; |
186 static bool check_fseek_ftell_workaround_needed (bool set_nonbuffered_mode) | 289 i = 0; |
187 { | 290 while (true) |
291 { | |
292 int c = fgetc (fptr); | |
293 | |
294 if (c == EOF) | |
295 { | |
296 (*current_liboctave_warning_handler) | |
297 ("fseek/ftell bug check failed (reading after repositioning)!"); | |
298 return false; | |
299 } | |
300 | |
301 if (c == '\n') | |
302 break; | |
303 | |
304 buf2[i++] = static_cast<char> (c); | |
305 } | |
306 buf2[i] = '\0'; | |
307 | |
308 return strcmp (buf1, buf2); | |
309 } | |
310 | |
311 #endif | |
312 | |
313 std::FILE * | |
314 fopen (const std::string& filename, const std::string& mode) | |
315 { | |
316 #if defined (OCTAVE_USE_WINDOWS_API) | |
317 | |
318 std::wstring wfilename = u8_to_wstring (filename); | |
319 std::wstring wmode = u8_to_wstring (mode); | |
320 | |
321 std::FILE *fptr = _wfopen (wfilename.c_str (), wmode.c_str ()); | |
322 | |
323 static bool fseek_ftell_bug_workaround_needed = false; | |
324 static bool fseek_ftell_bug_checked = false; | |
325 | |
326 if (! fseek_ftell_bug_checked && mode.find ('t') != std::string::npos) | |
327 { | |
328 // FIXME: Is the following workaround needed for all files | |
329 // opened in text mode, or only for files opened for reading? | |
330 | |
331 // Try to avoid fseek/ftell bug on Windows systems by setting | |
332 // non-buffered input mode for files opened in text mode, but | |
333 // only if it appears that the workaround is needed. See | |
334 // Octave bug #58055. | |
335 | |
188 // To check whether the workaround is needed: | 336 // To check whether the workaround is needed: |
189 // | 337 // |
190 // * Create a tmp file with LF line endings only. | 338 // * Create a tmp file with LF line endings only. |
191 // | 339 // |
192 // * Open that file for reading in text mode. | 340 // * Open that file for reading in text mode. |
193 // | 341 // |
194 // * Read a line. | 342 // * Read a line. |
195 // | 343 // |
196 // * Use ftello to record the position of the beginning of the | 344 // * Use ftello to record the position of the beginning of |
197 // second line. | 345 // the second line. |
198 // | 346 // |
199 // * Read and save the contents of the second line. | 347 // * Read and save the contents of the second line. |
200 // | 348 // |
201 // * Use fseeko to return to the saved position. | 349 // * Use fseeko to return to the saved position. |
202 // | 350 // |
203 // * Read the second line again and compare to the previously | 351 // * Read the second line again and compare to the |
204 // saved text. | 352 // previously saved text. |
205 // | 353 // |
206 // * If the lines are different, we need to set non-buffered | 354 // * If the lines are different, we need to set non-buffered |
207 // input mode for files opened in text mode. | 355 // input mode for files opened in text mode. |
208 | 356 // |
209 std::string tmpname = sys::tempnam ("", "oct-"); | 357 // * To verify that the workaround solves the problem, |
210 | 358 // repeat the above test with non-buffered input mode. If |
211 if (tmpname.empty ()) | 359 // that fails, warn that there may be trouble with |
360 // ftell/fseek when reading files opened in text mode. | |
361 | |
362 if (check_fseek_ftell_workaround_needed (false)) | |
212 { | 363 { |
213 (*current_liboctave_warning_handler) | 364 if (check_fseek_ftell_workaround_needed (true)) |
214 ("fseek/ftell bug check failed (tmp name creation)!"); | 365 (*current_liboctave_warning_handler) |
215 return false; | 366 ("fseek/ftell may fail for files opened in text mode"); |
367 else | |
368 fseek_ftell_bug_workaround_needed = true; | |
216 } | 369 } |
217 | 370 |
218 std::FILE *fptr = std::fopen (tmpname.c_str (), "wb"); | 371 fseek_ftell_bug_checked = true; |
219 | 372 } |
220 if (! fptr) | 373 |
374 if (fseek_ftell_bug_workaround_needed | |
375 && mode.find ('t') != std::string::npos) | |
376 ::setvbuf (fptr, nullptr, _IONBF, 0); | |
377 | |
378 return fptr; | |
379 | |
380 #else | |
381 return std::fopen (filename.c_str (), mode.c_str ()); | |
382 #endif | |
383 } | |
384 | |
385 std::FILE * | |
386 fopen_tmp (const std::string& name, const std::string& mode) | |
387 { | |
388 #if defined (OCTAVE_USE_WINDOWS_API) | |
389 | |
390 // Append "D" to the mode string to indicate that this is a temporary | |
391 // file that should be deleted when the last open handle is closed. | |
392 std::string tmp_mode = mode + "D"; | |
393 | |
394 return std::fopen (name.c_str (), tmp_mode.c_str ()); | |
395 | |
396 #else | |
397 | |
398 std::FILE *fptr = std::fopen (name.c_str (), mode.c_str ()); | |
399 | |
400 // From gnulib: This relies on the Unix semantics that a file is not | |
401 // really removed until it is closed. | |
402 octave_unlink_wrapper (name.c_str ()); | |
403 | |
404 return fptr; | |
405 | |
406 #endif | |
407 } | |
408 | |
409 std::fstream | |
410 fstream (const std::string& filename, const std::ios::openmode mode) | |
411 { | |
412 #if defined (OCTAVE_USE_WINDOWS_API) | |
413 | |
414 std::wstring wfilename = u8_to_wstring (filename); | |
415 | |
416 return std::fstream (wfilename.c_str (), mode); | |
417 | |
418 #else | |
419 return std::fstream (filename.c_str (), mode); | |
420 #endif | |
421 } | |
422 | |
423 std::ifstream | |
424 ifstream (const std::string& filename, const std::ios::openmode mode) | |
425 { | |
426 #if defined (OCTAVE_USE_WINDOWS_API) | |
427 | |
428 std::wstring wfilename = u8_to_wstring (filename); | |
429 | |
430 return std::ifstream (wfilename.c_str (), mode); | |
431 | |
432 #else | |
433 return std::ifstream (filename.c_str (), mode); | |
434 #endif | |
435 } | |
436 | |
437 std::ofstream | |
438 ofstream (const std::string& filename, const std::ios::openmode mode) | |
439 { | |
440 #if defined (OCTAVE_USE_WINDOWS_API) | |
441 | |
442 std::wstring wfilename = u8_to_wstring (filename); | |
443 | |
444 return std::ofstream (wfilename.c_str (), mode); | |
445 | |
446 #else | |
447 return std::ofstream (filename.c_str (), mode); | |
448 #endif | |
449 } | |
450 | |
451 void | |
452 putenv_wrapper (const std::string& name, const std::string& value) | |
453 { | |
454 std::string new_env = name + "=" + value; | |
455 | |
456 // FIXME: The malloc leaks memory, but so would a call to setenv. | |
457 // Short of extreme measures to track memory, altering the environment | |
458 // always leaks memory, but the saving grace is that the leaks are small. | |
459 | |
460 // As far as I can see there's no way to distinguish between the | |
461 // various errors; putenv doesn't have errno values. | |
462 | |
463 #if defined (OCTAVE_USE_WINDOWS_API) | |
464 std::wstring new_wenv = u8_to_wstring (new_env); | |
465 | |
466 int len = (new_wenv.length () + 1) * sizeof (wchar_t); | |
467 | |
468 wchar_t *new_item = static_cast<wchar_t *> (std::malloc (len)); | |
469 | |
470 wcscpy (new_item, new_wenv.c_str()); | |
471 | |
472 if (_wputenv (new_item) < 0) | |
473 (*current_liboctave_error_handler) | |
474 ("putenv (%s) failed", new_env.c_str()); | |
475 #else | |
476 int len = new_env.length () + 1; | |
477 | |
478 char *new_item = static_cast<char *> (std::malloc (len)); | |
479 | |
480 std::strcpy (new_item, new_env.c_str()); | |
481 | |
482 if (octave_putenv_wrapper (new_item) < 0) | |
483 (*current_liboctave_error_handler) ("putenv (%s) failed", new_item); | |
484 #endif | |
485 } | |
486 | |
487 std::string | |
488 getenv_wrapper (const std::string& name) | |
489 { | |
490 #if defined (OCTAVE_USE_WINDOWS_API) | |
491 std::wstring wname = u8_to_wstring (name); | |
492 wchar_t *env = _wgetenv (wname.c_str ()); | |
493 return env ? u8_from_wstring (env) : ""; | |
494 #else | |
495 char *env = ::getenv (name.c_str ()); | |
496 return env ? env : ""; | |
497 #endif | |
498 } | |
499 | |
500 int | |
501 unsetenv_wrapper (const std::string& name) | |
502 { | |
503 #if defined (OCTAVE_USE_WINDOWS_API) | |
504 putenv_wrapper (name, ""); | |
505 | |
506 std::wstring wname = u8_to_wstring (name); | |
507 return (SetEnvironmentVariableW (wname.c_str (), nullptr) ? 0 : -1); | |
508 #else | |
509 return octave_unsetenv_wrapper (name.c_str ()); | |
510 #endif | |
511 } | |
512 | |
513 std::wstring | |
514 u8_to_wstring (const std::string& utf8_string) | |
515 { | |
516 // convert multibyte UTF-8 string to wide character string | |
517 static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> | |
518 wchar_conv; | |
519 | |
520 std::wstring retval = L""; | |
521 | |
522 try | |
523 { | |
524 retval = wchar_conv.from_bytes (utf8_string); | |
525 } | |
526 catch (const std::range_error& e) | |
527 { | |
528 // What to do in case of error? | |
529 // error ("u8_to_wstring: converting from UTF-8 to wchar_t: %s", | |
530 // e.what ()); | |
531 } | |
532 | |
533 return retval; | |
534 } | |
535 | |
536 std::string | |
537 u8_from_wstring (const std::wstring& wchar_string) | |
538 { | |
539 // convert wide character string to multibyte UTF-8 string | |
540 static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> | |
541 wchar_conv; | |
542 | |
543 std::string retval = ""; | |
544 | |
545 try | |
546 { | |
547 retval = wchar_conv.to_bytes (wchar_string); | |
548 } | |
549 catch (const std::range_error& e) | |
550 { | |
551 // What to do in case of error? | |
552 // error ("u8_from_wstring: converting from wchar_t to UTF-8: %s", | |
553 // e.what ()); | |
554 } | |
555 | |
556 return retval; | |
557 } | |
558 | |
559 // At quite a few places in the code we are passing file names as | |
560 // char arrays to external library functions. | |
561 | |
562 // When these functions try to locate the corresponding file on the | |
563 // disc, they need to use the wide character API on Windows to | |
564 // correctly open files with non-ASCII characters. | |
565 | |
566 // But they have no way of knowing which encoding we are using for | |
567 // the passed string. So they have no way of reliably converting to | |
568 // a wchar_t array. (I.e. there is no possible fix for these | |
569 // functions with current C or C++.) | |
570 | |
571 // To solve the dilemma, the function "get_ASCII_filename" first | |
572 // checks whether there are any non-ASCII characters in the passed | |
573 // file name. If there are not, it returns the original name. | |
574 | |
575 // Otherwise, it optionally tries to convert the file name to the locale | |
576 // charset. | |
577 | |
578 // If the file name contains characters that cannot be converted to the | |
579 // locale charset (or that step is skipped), it tries to obtain the short | |
580 // file name (8.3 naming scheme) which only consists of ASCII characters | |
581 // and are safe to pass. However, short file names can be disabled for | |
582 // performance reasons on the file system level with NTFS and they are not | |
583 // stored on other file systems (e.g. ExFAT). So there is no guarantee | |
584 // that these exist. | |
585 | |
586 // If short file names are not stored, a hard link to the file is | |
587 // created. For this the path to the file is split at the deepest | |
588 // possible level that doesn't contain non-ASCII characters. At | |
589 // that level a hidden folder is created that holds the hard links. | |
590 // That means we need to have write access on that location. A path | |
591 // to that hard link is returned. | |
592 | |
593 // If the file system is FAT32, there are no hard links. But FAT32 | |
594 // always stores short file names. So we are safe. | |
595 | |
596 // ExFAT that is occasionally used on USB sticks and SD cards stores | |
597 // neither short file names nor does it support hard links. So for | |
598 // exFAT with this function, there is (currently) no way to generate | |
599 // a file name that is stripped from non-ASCII characters but still | |
600 // is valid. | |
601 | |
602 // For Unixy systems, this function does nothing. | |
603 | |
604 std::string | |
605 get_ASCII_filename (const std::string& orig_file_name, | |
606 const bool allow_locale) | |
607 { | |
608 #if defined (OCTAVE_USE_WINDOWS_API) | |
609 | |
610 // Return file name that only contains ASCII characters that can | |
611 // be used to access the file orig_file_name. The original file | |
612 // must exist in the file system before calling this function. | |
613 // This is useful for passing file names to functions that are not | |
614 // aware of the character encoding we are using. | |
615 | |
616 // 0. Check whether filename contains non-ASCII (UTF-8) characters. | |
617 | |
618 std::string::const_iterator first_non_ASCII | |
619 = std::find_if (orig_file_name.begin (), orig_file_name.end (), | |
620 [](char c) { return (c < 0 || c >= 128); }); | |
621 | |
622 if (first_non_ASCII == orig_file_name.end ()) | |
623 return orig_file_name; | |
624 | |
625 // 1. Optionally, check if all characters in the path can be successfully | |
626 // converted to the locale charset | |
627 if (allow_locale) | |
628 { | |
629 const char *locale = octave_locale_charset_wrapper (); | |
630 if (locale) | |
221 { | 631 { |
222 (*current_liboctave_warning_handler) | 632 const uint8_t *name_u8 = reinterpret_cast<const uint8_t *> |
223 ("fseek/ftell bug check failed (opening tmp file for writing)!"); | 633 (orig_file_name.c_str ()); |
224 return false; | 634 std::size_t length = 0; |
225 } | 635 char *name_locale = octave_u8_conv_to_encoding_strict |
226 | 636 (locale, name_u8, |
227 fprintf (fptr, "%s", "foo\nbar\nbaz\n"); | 637 orig_file_name.length () + 1, &length); |
228 | 638 if (name_locale) |
229 std::fclose (fptr); | |
230 | |
231 fptr = std::fopen (tmpname.c_str (), "rt"); | |
232 | |
233 if (! fptr) | |
234 { | |
235 (*current_liboctave_warning_handler) | |
236 ("fseek/ftell bug check failed (opening tmp file for reading)!"); | |
237 return false; | |
238 } | |
239 | |
240 unwind_action act ([=] () | |
241 { | |
242 std::fclose (fptr); | |
243 sys::unlink (tmpname); | |
244 }); | |
245 | |
246 if (set_nonbuffered_mode) | |
247 ::setvbuf (fptr, nullptr, _IONBF, 0); | |
248 | |
249 while (true) | |
250 { | |
251 int c = fgetc (fptr); | |
252 | |
253 if (c == EOF) | |
254 { | 639 { |
255 (*current_liboctave_warning_handler) | 640 std::string file_name_locale (name_locale, length); |
256 ("fseek/ftell bug check failed (skipping first line)!"); | 641 free (name_locale); |
257 return false; | 642 return file_name_locale; |
258 } | |
259 | |
260 if (c == '\n') | |
261 break; | |
262 } | |
263 | |
264 off_t pos = octave_ftello_wrapper (fptr); | |
265 | |
266 char buf1[8]; | |
267 int i = 0; | |
268 while (true) | |
269 { | |
270 int c = fgetc (fptr); | |
271 | |
272 if (c == EOF) | |
273 { | |
274 (*current_liboctave_warning_handler) | |
275 ("fseek/ftell bug check failed (reading second line)!"); | |
276 return false; | |
277 } | |
278 | |
279 if (c == '\n') | |
280 break; | |
281 | |
282 buf1[i++] = static_cast<char> (c); | |
283 } | |
284 buf1[i] = '\0'; | |
285 | |
286 octave_fseeko_wrapper (fptr, pos, SEEK_SET); | |
287 | |
288 char buf2[8]; | |
289 i = 0; | |
290 while (true) | |
291 { | |
292 int c = fgetc (fptr); | |
293 | |
294 if (c == EOF) | |
295 { | |
296 (*current_liboctave_warning_handler) | |
297 ("fseek/ftell bug check failed (reading after repositioning)!"); | |
298 return false; | |
299 } | |
300 | |
301 if (c == '\n') | |
302 break; | |
303 | |
304 buf2[i++] = static_cast<char> (c); | |
305 } | |
306 buf2[i] = '\0'; | |
307 | |
308 return strcmp (buf1, buf2); | |
309 } | |
310 | |
311 #endif | |
312 | |
313 std::FILE * | |
314 fopen (const std::string& filename, const std::string& mode) | |
315 { | |
316 #if defined (OCTAVE_USE_WINDOWS_API) | |
317 | |
318 std::wstring wfilename = u8_to_wstring (filename); | |
319 std::wstring wmode = u8_to_wstring (mode); | |
320 | |
321 std::FILE *fptr = _wfopen (wfilename.c_str (), wmode.c_str ()); | |
322 | |
323 static bool fseek_ftell_bug_workaround_needed = false; | |
324 static bool fseek_ftell_bug_checked = false; | |
325 | |
326 if (! fseek_ftell_bug_checked && mode.find ('t') != std::string::npos) | |
327 { | |
328 // FIXME: Is the following workaround needed for all files | |
329 // opened in text mode, or only for files opened for reading? | |
330 | |
331 // Try to avoid fseek/ftell bug on Windows systems by setting | |
332 // non-buffered input mode for files opened in text mode, but | |
333 // only if it appears that the workaround is needed. See | |
334 // Octave bug #58055. | |
335 | |
336 // To check whether the workaround is needed: | |
337 // | |
338 // * Create a tmp file with LF line endings only. | |
339 // | |
340 // * Open that file for reading in text mode. | |
341 // | |
342 // * Read a line. | |
343 // | |
344 // * Use ftello to record the position of the beginning of | |
345 // the second line. | |
346 // | |
347 // * Read and save the contents of the second line. | |
348 // | |
349 // * Use fseeko to return to the saved position. | |
350 // | |
351 // * Read the second line again and compare to the | |
352 // previously saved text. | |
353 // | |
354 // * If the lines are different, we need to set non-buffered | |
355 // input mode for files opened in text mode. | |
356 // | |
357 // * To verify that the workaround solves the problem, | |
358 // repeat the above test with non-buffered input mode. If | |
359 // that fails, warn that there may be trouble with | |
360 // ftell/fseek when reading files opened in text mode. | |
361 | |
362 if (check_fseek_ftell_workaround_needed (false)) | |
363 { | |
364 if (check_fseek_ftell_workaround_needed (true)) | |
365 (*current_liboctave_warning_handler) | |
366 ("fseek/ftell may fail for files opened in text mode"); | |
367 else | |
368 fseek_ftell_bug_workaround_needed = true; | |
369 } | |
370 | |
371 fseek_ftell_bug_checked = true; | |
372 } | |
373 | |
374 if (fseek_ftell_bug_workaround_needed | |
375 && mode.find ('t') != std::string::npos) | |
376 ::setvbuf (fptr, nullptr, _IONBF, 0); | |
377 | |
378 return fptr; | |
379 | |
380 #else | |
381 return std::fopen (filename.c_str (), mode.c_str ()); | |
382 #endif | |
383 } | |
384 | |
385 std::FILE * | |
386 fopen_tmp (const std::string& name, const std::string& mode) | |
387 { | |
388 #if defined (OCTAVE_USE_WINDOWS_API) | |
389 | |
390 // Append "D" to the mode string to indicate that this is a temporary | |
391 // file that should be deleted when the last open handle is closed. | |
392 std::string tmp_mode = mode + "D"; | |
393 | |
394 return std::fopen (name.c_str (), tmp_mode.c_str ()); | |
395 | |
396 #else | |
397 | |
398 std::FILE *fptr = std::fopen (name.c_str (), mode.c_str ()); | |
399 | |
400 // From gnulib: This relies on the Unix semantics that a file is not | |
401 // really removed until it is closed. | |
402 octave_unlink_wrapper (name.c_str ()); | |
403 | |
404 return fptr; | |
405 | |
406 #endif | |
407 } | |
408 | |
409 std::fstream | |
410 fstream (const std::string& filename, const std::ios::openmode mode) | |
411 { | |
412 #if defined (OCTAVE_USE_WINDOWS_API) | |
413 | |
414 std::wstring wfilename = u8_to_wstring (filename); | |
415 | |
416 return std::fstream (wfilename.c_str (), mode); | |
417 | |
418 #else | |
419 return std::fstream (filename.c_str (), mode); | |
420 #endif | |
421 } | |
422 | |
423 std::ifstream | |
424 ifstream (const std::string& filename, const std::ios::openmode mode) | |
425 { | |
426 #if defined (OCTAVE_USE_WINDOWS_API) | |
427 | |
428 std::wstring wfilename = u8_to_wstring (filename); | |
429 | |
430 return std::ifstream (wfilename.c_str (), mode); | |
431 | |
432 #else | |
433 return std::ifstream (filename.c_str (), mode); | |
434 #endif | |
435 } | |
436 | |
437 std::ofstream | |
438 ofstream (const std::string& filename, const std::ios::openmode mode) | |
439 { | |
440 #if defined (OCTAVE_USE_WINDOWS_API) | |
441 | |
442 std::wstring wfilename = u8_to_wstring (filename); | |
443 | |
444 return std::ofstream (wfilename.c_str (), mode); | |
445 | |
446 #else | |
447 return std::ofstream (filename.c_str (), mode); | |
448 #endif | |
449 } | |
450 | |
451 void | |
452 putenv_wrapper (const std::string& name, const std::string& value) | |
453 { | |
454 std::string new_env = name + "=" + value; | |
455 | |
456 // FIXME: The malloc leaks memory, but so would a call to setenv. | |
457 // Short of extreme measures to track memory, altering the environment | |
458 // always leaks memory, but the saving grace is that the leaks are small. | |
459 | |
460 // As far as I can see there's no way to distinguish between the | |
461 // various errors; putenv doesn't have errno values. | |
462 | |
463 #if defined (OCTAVE_USE_WINDOWS_API) | |
464 std::wstring new_wenv = u8_to_wstring (new_env); | |
465 | |
466 int len = (new_wenv.length () + 1) * sizeof (wchar_t); | |
467 | |
468 wchar_t *new_item = static_cast<wchar_t *> (std::malloc (len)); | |
469 | |
470 wcscpy (new_item, new_wenv.c_str()); | |
471 | |
472 if (_wputenv (new_item) < 0) | |
473 (*current_liboctave_error_handler) | |
474 ("putenv (%s) failed", new_env.c_str()); | |
475 #else | |
476 int len = new_env.length () + 1; | |
477 | |
478 char *new_item = static_cast<char *> (std::malloc (len)); | |
479 | |
480 std::strcpy (new_item, new_env.c_str()); | |
481 | |
482 if (octave_putenv_wrapper (new_item) < 0) | |
483 (*current_liboctave_error_handler) ("putenv (%s) failed", new_item); | |
484 #endif | |
485 } | |
486 | |
487 std::string | |
488 getenv_wrapper (const std::string& name) | |
489 { | |
490 #if defined (OCTAVE_USE_WINDOWS_API) | |
491 std::wstring wname = u8_to_wstring (name); | |
492 wchar_t *env = _wgetenv (wname.c_str ()); | |
493 return env ? u8_from_wstring (env) : ""; | |
494 #else | |
495 char *env = ::getenv (name.c_str ()); | |
496 return env ? env : ""; | |
497 #endif | |
498 } | |
499 | |
500 int | |
501 unsetenv_wrapper (const std::string& name) | |
502 { | |
503 #if defined (OCTAVE_USE_WINDOWS_API) | |
504 putenv_wrapper (name, ""); | |
505 | |
506 std::wstring wname = u8_to_wstring (name); | |
507 return (SetEnvironmentVariableW (wname.c_str (), nullptr) ? 0 : -1); | |
508 #else | |
509 return octave_unsetenv_wrapper (name.c_str ()); | |
510 #endif | |
511 } | |
512 | |
513 std::wstring | |
514 u8_to_wstring (const std::string& utf8_string) | |
515 { | |
516 // convert multibyte UTF-8 string to wide character string | |
517 static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> | |
518 wchar_conv; | |
519 | |
520 std::wstring retval = L""; | |
521 | |
522 try | |
523 { | |
524 retval = wchar_conv.from_bytes (utf8_string); | |
525 } | |
526 catch (const std::range_error& e) | |
527 { | |
528 // What to do in case of error? | |
529 // error ("u8_to_wstring: converting from UTF-8 to wchar_t: %s", | |
530 // e.what ()); | |
531 } | |
532 | |
533 return retval; | |
534 } | |
535 | |
536 std::string | |
537 u8_from_wstring (const std::wstring& wchar_string) | |
538 { | |
539 // convert wide character string to multibyte UTF-8 string | |
540 static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> | |
541 wchar_conv; | |
542 | |
543 std::string retval = ""; | |
544 | |
545 try | |
546 { | |
547 retval = wchar_conv.to_bytes (wchar_string); | |
548 } | |
549 catch (const std::range_error& e) | |
550 { | |
551 // What to do in case of error? | |
552 // error ("u8_from_wstring: converting from wchar_t to UTF-8: %s", | |
553 // e.what ()); | |
554 } | |
555 | |
556 return retval; | |
557 } | |
558 | |
559 // At quite a few places in the code we are passing file names as | |
560 // char arrays to external library functions. | |
561 | |
562 // When these functions try to locate the corresponding file on the | |
563 // disc, they need to use the wide character API on Windows to | |
564 // correctly open files with non-ASCII characters. | |
565 | |
566 // But they have no way of knowing which encoding we are using for | |
567 // the passed string. So they have no way of reliably converting to | |
568 // a wchar_t array. (I.e. there is no possible fix for these | |
569 // functions with current C or C++.) | |
570 | |
571 // To solve the dilemma, the function "get_ASCII_filename" first | |
572 // checks whether there are any non-ASCII characters in the passed | |
573 // file name. If there are not, it returns the original name. | |
574 | |
575 // Otherwise, it optionally tries to convert the file name to the locale | |
576 // charset. | |
577 | |
578 // If the file name contains characters that cannot be converted to the | |
579 // locale charset (or that step is skipped), it tries to obtain the short | |
580 // file name (8.3 naming scheme) which only consists of ASCII characters | |
581 // and are safe to pass. However, short file names can be disabled for | |
582 // performance reasons on the file system level with NTFS and they are not | |
583 // stored on other file systems (e.g. ExFAT). So there is no guarantee | |
584 // that these exist. | |
585 | |
586 // If short file names are not stored, a hard link to the file is | |
587 // created. For this the path to the file is split at the deepest | |
588 // possible level that doesn't contain non-ASCII characters. At | |
589 // that level a hidden folder is created that holds the hard links. | |
590 // That means we need to have write access on that location. A path | |
591 // to that hard link is returned. | |
592 | |
593 // If the file system is FAT32, there are no hard links. But FAT32 | |
594 // always stores short file names. So we are safe. | |
595 | |
596 // ExFAT that is occasionally used on USB sticks and SD cards stores | |
597 // neither short file names nor does it support hard links. So for | |
598 // exFAT with this function, there is (currently) no way to generate | |
599 // a file name that is stripped from non-ASCII characters but still | |
600 // is valid. | |
601 | |
602 // For Unixy systems, this function does nothing. | |
603 | |
604 std::string | |
605 get_ASCII_filename (const std::string& orig_file_name, | |
606 const bool allow_locale) | |
607 { | |
608 #if defined (OCTAVE_USE_WINDOWS_API) | |
609 | |
610 // Return file name that only contains ASCII characters that can | |
611 // be used to access the file orig_file_name. The original file | |
612 // must exist in the file system before calling this function. | |
613 // This is useful for passing file names to functions that are not | |
614 // aware of the character encoding we are using. | |
615 | |
616 // 0. Check whether filename contains non-ASCII (UTF-8) characters. | |
617 | |
618 std::string::const_iterator first_non_ASCII | |
619 = std::find_if (orig_file_name.begin (), orig_file_name.end (), | |
620 [](char c) { return (c < 0 || c >= 128); }); | |
621 | |
622 if (first_non_ASCII == orig_file_name.end ()) | |
623 return orig_file_name; | |
624 | |
625 // 1. Optionally, check if all characters in the path can be successfully | |
626 // converted to the locale charset | |
627 if (allow_locale) | |
628 { | |
629 const char *locale = octave_locale_charset_wrapper (); | |
630 if (locale) | |
631 { | |
632 const uint8_t *name_u8 = reinterpret_cast<const uint8_t *> | |
633 (orig_file_name.c_str ()); | |
634 std::size_t length = 0; | |
635 char *name_locale = octave_u8_conv_to_encoding_strict | |
636 (locale, name_u8, | |
637 orig_file_name.length () + 1, &length); | |
638 if (name_locale) | |
639 { | |
640 std::string file_name_locale (name_locale, length); | |
641 free (name_locale); | |
642 return file_name_locale; | |
643 } | |
644 } | 643 } |
645 } | 644 } |
646 | 645 } |
647 // 2. Check if file system stores short filenames (might be ASCII-only). | 646 |
648 | 647 // 2. Check if file system stores short filenames (might be ASCII-only). |
649 std::wstring w_orig_file_name_str = u8_to_wstring (orig_file_name); | 648 |
650 const wchar_t *w_orig_file_name = w_orig_file_name_str.c_str (); | 649 std::wstring w_orig_file_name_str = u8_to_wstring (orig_file_name); |
651 | 650 const wchar_t *w_orig_file_name = w_orig_file_name_str.c_str (); |
652 // Get full path to file | 651 |
653 wchar_t w_full_file_name[_MAX_PATH]; | 652 // Get full path to file |
654 if (_wfullpath (w_full_file_name, w_orig_file_name, _MAX_PATH) == nullptr) | 653 wchar_t w_full_file_name[_MAX_PATH]; |
654 if (_wfullpath (w_full_file_name, w_orig_file_name, _MAX_PATH) == nullptr) | |
655 return orig_file_name; | |
656 | |
657 std::wstring w_full_file_name_str = w_full_file_name; | |
658 | |
659 // Get short filename (8.3) from UTF-16 filename. | |
660 | |
661 long length = GetShortPathNameW (w_full_file_name, nullptr, 0); | |
662 | |
663 if (length > 0) | |
664 { | |
665 // Dynamically allocate the correct size (terminating null char | |
666 // was included in length). | |
667 | |
668 OCTAVE_LOCAL_BUFFER (wchar_t, w_short_file_name, length); | |
669 GetShortPathNameW (w_full_file_name, w_short_file_name, length); | |
670 | |
671 std::wstring w_short_file_name_str | |
672 = std::wstring (w_short_file_name, length); | |
673 | |
674 if (w_short_file_name_str.compare (0, length-1, w_full_file_name_str) != 0) | |
675 { | |
676 // Check whether short file name contains non-ASCII characters | |
677 std::string short_file_name | |
678 = u8_from_wstring (w_short_file_name_str); | |
679 first_non_ASCII | |
680 = std::find_if (short_file_name.begin (), | |
681 short_file_name.end (), | |
682 [](char c) { return (c < 0 || c >= 128); }); | |
683 if (first_non_ASCII == short_file_name.end ()) | |
684 return short_file_name; | |
685 } | |
686 } | |
687 | |
688 // 3. Create hard link with only-ASCII characters. | |
689 // Get longest possible part of path that only contains ASCII chars. | |
690 | |
691 std::wstring::iterator w_first_non_ASCII | |
692 = std::find_if (w_full_file_name_str.begin (), w_full_file_name_str.end (), | |
693 [](wchar_t c) { return (c < 0 || c >= 128); }); | |
694 std::wstring tmp_substr | |
695 = std::wstring (w_full_file_name_str.begin (), w_first_non_ASCII); | |
696 | |
697 std::size_t pos | |
698 = tmp_substr.find_last_of (u8_to_wstring (file_ops::dir_sep_chars ())); | |
699 | |
700 std::string par_dir | |
701 = u8_from_wstring (w_full_file_name_str.substr (0, pos+1)); | |
702 | |
703 // Create .oct_ascii directory. | |
704 // FIXME: We need to have write permission in this location. | |
705 | |
706 std::string oct_ascii_dir = par_dir + ".oct_ascii"; | |
707 std::string test_dir = canonicalize_file_name (oct_ascii_dir); | |
708 | |
709 if (test_dir.empty ()) | |
710 { | |
711 std::string msg; | |
712 int status = sys::mkdir (oct_ascii_dir, 0777, msg); | |
713 | |
714 if (status < 0) | |
655 return orig_file_name; | 715 return orig_file_name; |
656 | 716 |
657 std::wstring w_full_file_name_str = w_full_file_name; | 717 // Set hidden property. |
658 | 718 SetFileAttributesA (oct_ascii_dir.c_str (), FILE_ATTRIBUTE_HIDDEN); |
659 // Get short filename (8.3) from UTF-16 filename. | 719 } |
660 | 720 |
661 long length = GetShortPathNameW (w_full_file_name, nullptr, 0); | 721 // Create file from hash of full filename. |
662 | 722 std::string filename_hash |
663 if (length > 0) | 723 = (oct_ascii_dir + file_ops::dir_sep_str () |
664 { | 724 + crypto::hash ("SHA1", orig_file_name)); |
665 // Dynamically allocate the correct size (terminating null char | 725 |
666 // was included in length). | 726 // FIXME: This is just to check if the file exists. Use a more efficient |
667 | 727 // method. |
668 OCTAVE_LOCAL_BUFFER (wchar_t, w_short_file_name, length); | 728 std::string abs_filename_hash = canonicalize_file_name (filename_hash); |
669 GetShortPathNameW (w_full_file_name, w_short_file_name, length); | 729 |
670 | 730 if (! abs_filename_hash.empty ()) |
671 std::wstring w_short_file_name_str | 731 sys::unlink (filename_hash); |
672 = std::wstring (w_short_file_name, length); | 732 |
673 | 733 // At this point, we know that we have only ASCII characters. |
674 if (w_short_file_name_str.compare (0, length-1, w_full_file_name_str) != 0) | 734 // So instead of converting, just copy the characters to std::wstring. |
675 { | 735 std::wstring w_filename_hash (filename_hash.begin (), |
676 // Check whether short file name contains non-ASCII characters | 736 filename_hash.end ()); |
677 std::string short_file_name | 737 |
678 = u8_from_wstring (w_short_file_name_str); | 738 if (CreateHardLinkW (w_filename_hash.c_str (), w_orig_file_name, nullptr)) |
679 first_non_ASCII | 739 return filename_hash; |
680 = std::find_if (short_file_name.begin (), | 740 |
681 short_file_name.end (), | 741 #else |
682 [](char c) { return (c < 0 || c >= 128); }); | 742 |
683 if (first_non_ASCII == short_file_name.end ()) | 743 octave_unused_parameter (allow_locale); |
684 return short_file_name; | 744 |
685 } | 745 #endif |
686 } | 746 |
687 | 747 return orig_file_name; |
688 // 3. Create hard link with only-ASCII characters. | 748 } |
689 // Get longest possible part of path that only contains ASCII chars. | |
690 | |
691 std::wstring::iterator w_first_non_ASCII | |
692 = std::find_if (w_full_file_name_str.begin (), w_full_file_name_str.end (), | |
693 [](wchar_t c) { return (c < 0 || c >= 128); }); | |
694 std::wstring tmp_substr | |
695 = std::wstring (w_full_file_name_str.begin (), w_first_non_ASCII); | |
696 | |
697 std::size_t pos | |
698 = tmp_substr.find_last_of (u8_to_wstring (file_ops::dir_sep_chars ())); | |
699 | |
700 std::string par_dir | |
701 = u8_from_wstring (w_full_file_name_str.substr (0, pos+1)); | |
702 | |
703 // Create .oct_ascii directory. | |
704 // FIXME: We need to have write permission in this location. | |
705 | |
706 std::string oct_ascii_dir = par_dir + ".oct_ascii"; | |
707 std::string test_dir = canonicalize_file_name (oct_ascii_dir); | |
708 | |
709 if (test_dir.empty ()) | |
710 { | |
711 std::string msg; | |
712 int status = sys::mkdir (oct_ascii_dir, 0777, msg); | |
713 | |
714 if (status < 0) | |
715 return orig_file_name; | |
716 | |
717 // Set hidden property. | |
718 SetFileAttributesA (oct_ascii_dir.c_str (), FILE_ATTRIBUTE_HIDDEN); | |
719 } | |
720 | |
721 // Create file from hash of full filename. | |
722 std::string filename_hash | |
723 = (oct_ascii_dir + file_ops::dir_sep_str () | |
724 + crypto::hash ("SHA1", orig_file_name)); | |
725 | |
726 // FIXME: This is just to check if the file exists. Use a more efficient | |
727 // method. | |
728 std::string abs_filename_hash = canonicalize_file_name (filename_hash); | |
729 | |
730 if (! abs_filename_hash.empty ()) | |
731 sys::unlink (filename_hash); | |
732 | |
733 // At this point, we know that we have only ASCII characters. | |
734 // So instead of converting, just copy the characters to std::wstring. | |
735 std::wstring w_filename_hash (filename_hash.begin (), | |
736 filename_hash.end ()); | |
737 | |
738 if (CreateHardLinkW (w_filename_hash.c_str (), w_orig_file_name, nullptr)) | |
739 return filename_hash; | |
740 | |
741 #else | |
742 | |
743 octave_unused_parameter (allow_locale); | |
744 | |
745 #endif | |
746 | |
747 return orig_file_name; | |
748 } | |
749 | 749 |
750 OCTAVE_END_NAMESPACE(sys) | 750 OCTAVE_END_NAMESPACE(sys) |
751 OCTAVE_END_NAMESPACE(octave) | 751 OCTAVE_END_NAMESPACE(octave) |