NEURON
ocfile.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #if defined(HAVE_UNISTD_H)
6 #include <unistd.h>
7 #endif
8 
9 #ifdef WIN32
10 #include <errno.h>
11 #include <io.h>
12 #include <fcntl.h>
13 #endif
14 #if HAVE_IV
15 #include "utility.h"
16 #include <IV-look/dialogs.h>
17 #include <InterViews/session.h>
18 #include <InterViews/display.h>
19 #include <InterViews/style.h>
20 #include <InterViews/resource.h>
21 #endif
22 #include "nrnmpi.h"
23 #include "oc2iv.h"
24 #include "code.h"
25 #include "classreg.h"
26 #include "ocfile.h"
27 #include "nrnfilewrap.h"
28 
29 // for isDirExist and makePath
30 #include <iostream>
31 #include <sys/stat.h>
32 #include <errno.h>
33 #if defined(_WIN32)
34 #include <direct.h>
35 #endif
36 
37 #include "gui-redirect.h"
38 
40 extern char* ivoc_get_temp_file();
41 static int ivoc_unlink(const char*);
42 int ivoc_unlink(const char* s) {
43  return unlink(s);
44 }
45 
46 #include "hocstr.h"
47 std::FILE* hoc_obj_file_arg(int i) {
48  Object* ob = *hoc_objgetarg(i);
49  check_obj_type(ob, "File");
50  OcFile* f = (OcFile*) (ob->u.this_pointer);
51  if (!f->is_open()) {
52  hoc_execerror("File not open:", f->get_name());
53  }
54  return f->file();
55 }
56 
58  : filename_("") {
59  file_ = NULL;
60  fc_ = NULL;
61 #ifdef WIN32
62  binary_ = false;
63 #endif
64 }
66 #if HAVE_IV
68 #endif
69  close();
70 }
71 
72 static double f_ropen(void* v) {
73  OcFile* f = (OcFile*) v;
74  if (ifarg(1)) {
75  f->set_name(gargstr(1));
76  }
77  return double(f->open(f->get_name(), "r"));
78 }
79 
80 static double f_wopen(void* v) {
81  OcFile* f = (OcFile*) v;
82  if (ifarg(1)) {
83  f->set_name(gargstr(1));
84  }
85  return double(f->open(f->get_name(), "w"));
86 }
87 
88 static double f_aopen(void* v) {
89  OcFile* f = (OcFile*) v;
90  if (ifarg(1)) {
91  f->set_name(gargstr(1));
92  }
93  int err = f->open(f->get_name(), "a");
94 #ifdef MINGW
95  /* ignore illegal seek */
96  if (err && errno == 29) {
97  errno = 0;
98  }
99 #endif
100  return double(err);
101 }
102 
103 static double f_printf(void* v) {
104  OcFile* f = (OcFile*) v;
105  char* buf;
106  hoc_sprint1(&buf, 1);
107  f->print(buf);
108  return 0.;
109 }
110 
111 static double f_scanvar(void* v) {
112  OcFile* f = (OcFile*) v;
113  return hoc_scan(f->file());
114 }
115 
116 static double f_scanstr(void* v) {
117  OcFile* f = (OcFile*) v;
118  char** pbuf = hoc_pgargstr(1);
119  char* buf = hoc_tmpbuf->buf;
120  int i = fscanf(f->file(), "%s", buf);
121  if (i == 1) {
122  hoc_assign_str(pbuf, buf);
123  return double(strlen(buf));
124  } else {
125  return -1.;
126  }
127 }
128 
129 static double f_gets(void* v) {
130  OcFile* f = (OcFile*) v;
131  char** pbuf = hoc_pgargstr(1);
132  char* buf;
133  FILE* fw = f->file();
134  if ((buf = fgets_unlimited(hoc_tmpbuf, fw)) != 0) {
135  hoc_assign_str(pbuf, buf);
136  return double(strlen(buf));
137  } else {
138  return -1.;
139  }
140 }
141 
142 static double f_mktemp(void* v) {
143  OcFile* f = (OcFile*) v;
144  return double(f->mktemp());
145 }
146 
147 static double f_unlink(void* v) {
148  OcFile* f = (OcFile*) v;
149  return double(f->unlink());
150 }
151 
152 static double f_eof(void* v) {
153  OcFile* f = (OcFile*) v;
154  return double(f->eof());
155 }
156 
157 static double f_is_open(void* v) {
158  OcFile* f = (OcFile*) v;
159  return double(f->is_open());
160 }
161 
162 static double f_flush(void* v) {
163  OcFile* f = (OcFile*) v;
164  f->flush();
165  return 1;
166 }
167 
168 static const char** f_get_name(void* v) {
169  OcFile* f = (OcFile*) v;
170  char** ps = hoc_temp_charptr();
171  *ps = (char*) f->get_name();
172  if (ifarg(1)) {
173  hoc_assign_str(hoc_pgargstr(1), *ps);
174  }
175  return (const char**) ps;
176 }
177 
178 static const char** f_dir(void* v) {
179  char** ps = hoc_temp_charptr();
180  OcFile* f = (OcFile*) v;
181  *ps = (char*) f->dir();
182  return (const char**) ps;
183 }
184 
185 static double f_chooser(void* v) {
187 #if HAVE_IV
188  if (hoc_usegui) {
189  OcFile* f = (OcFile*) v;
190  f->close();
191 
192  if (!ifarg(1)) {
193  return double(f->file_chooser_popup());
194  }
195 
196  char *type, *banner, *filter, *bopen, *cancel;
197  banner = filter = bopen = cancel = NULL;
198  const char* path = ".";
199  type = gargstr(1);
200  if (ifarg(2)) {
201  banner = gargstr(2);
202  }
203  if (ifarg(3)) {
204  filter = gargstr(3);
205  }
206  if (ifarg(4)) {
207  bopen = gargstr(4);
208  }
209  if (ifarg(5)) {
210  cancel = gargstr(5);
211  }
212  if (ifarg(6)) {
213  path = gargstr(6);
214  }
215 
216  f->file_chooser_style(type, path, banner, filter, bopen, cancel);
217  }
218 #endif
219  return 1.;
220 }
221 
222 static double f_close(void* v) {
223  OcFile* f = (OcFile*) v;
224  f->close();
225  return 0.;
226 }
227 
228 static double f_vwrite(void* v) {
229  OcFile* f = (OcFile*) v;
230  size_t n = 1;
231  if (ifarg(2))
232  n = long(chkarg(1, 1., 2.e18));
233  const char* x = (const char*) hoc_pgetarg(ifarg(2) + 1);
234  BinaryMode(f) return (double) fwrite(x, sizeof(double), n, f->file());
235 }
236 
237 static double f_vread(void* v) {
238  OcFile* f = (OcFile*) v;
239  size_t n = 1;
240  if (ifarg(2))
241  n = int(chkarg(1, 1., 2.e18));
242  char* x = (char*) hoc_pgetarg(ifarg(2) + 1);
243  BinaryMode(f) return (double) fread(x, sizeof(double), n, f->file());
244 }
245 
246 static double f_seek(void* v) {
247  OcFile* f = (OcFile*) v;
248  long n = 0;
249  int base = 0;
250  if (ifarg(1)) {
251  // no longer check since since many machines have >2GB files
252  n = long(*getarg(1));
253  }
254  if (ifarg(2)) {
255  base = int(chkarg(2, 0., 2.));
256  }
257  BinaryMode(f) return (double) fseek(f->file(), n, base);
258 }
259 
260 static double f_tell(void* v) {
261  OcFile* f = (OcFile*) v;
263  BinaryMode(f) return (double) ftell(f->file());
264 }
265 
266 static void* f_cons(Object*) {
267  OcFile* f = new OcFile();
268  if (ifarg(1)) {
269  f->set_name(gargstr(1));
270  }
271  return f;
272 }
273 
274 static void f_destruct(void* v) {
275  delete (OcFile*) v;
276 }
277 
278 Member_func f_members[] = {{"ropen", f_ropen},
279  {"wopen", f_wopen},
280  {"aopen", f_aopen},
281  {"printf", f_printf},
282  {"scanvar", f_scanvar},
283  {"scanstr", f_scanstr},
284  {"gets", f_gets},
285  {"eof", f_eof},
286  {"isopen", f_is_open},
287  {"chooser", f_chooser},
288  {"close", f_close},
289  {"vwrite", f_vwrite},
290  {"vread", f_vread},
291  {"seek", f_seek},
292  {"tell", f_tell},
293  {"mktemp", f_mktemp},
294  {"unlink", f_unlink},
295  {"flush", f_flush},
296  {nullptr, nullptr}};
297 
299  {"dir", f_dir},
300  {nullptr, nullptr}};
301 
302 void OcFile_reg() {
303  class2oc("File", f_cons, f_destruct, f_members, nullptr, f_retstr_members);
304  file_class_sym_ = hoc_lookup("File");
305 }
306 
308  if (file_) {
309  fclose(file_);
310  }
311  file_ = NULL;
312 }
313 void OcFile::set_name(const char* s) {
314  close();
315  if (s != filename_.c_str()) {
316  filename_ = s;
317  }
318 }
319 
320 #ifdef WIN32
321 void OcFile::binary_mode() {
322  if (file() && !binary_) {
323  if (ftell(file()) != 0) {
325  ":can switch to dos binary file mode only at beginning of file.\n\
326  Use File.seek(0) after opening or use a binary style read/write as first\n\
327  access to file.");
328  }
329  setmode(fileno(file()), O_BINARY);
330  binary_ = true;
331  }
332 }
333 #endif
334 
335 bool OcFile::open(const char* name, const char* type) {
336  set_name(name);
337 #ifdef WIN32
338  binary_ = false;
339  strcpy(mode_, type);
340 #endif
341  file_ = fopen(expand_env_var(name), type);
342  return is_open();
343 }
344 
345 FILE* OcFile::file() {
346  if (!file_) {
347  hoc_execerror(get_name(), ":file is not open");
348  }
349  return file_;
350 }
351 
352 bool OcFile::eof() {
353  int c;
354  c = getc(file());
355  return ungetc(c, file()) == EOF;
356 }
357 
359  char* s = ivoc_get_temp_file();
360  if (s) {
361  set_name(s);
362  delete[] s;
363  return true;
364  }
365  return false;
366 }
367 
369  int i = ivoc_unlink(get_name());
370  return i == 0;
371 }
372 
374  const char* path,
375  const char* banner,
376  const char* filter,
377  const char* bopen,
378  const char* cancel) {
379 #if HAVE_IV
381 
382  Style* style = new Style(Session::instance()->style());
383  style->ref();
384  bool nocap = true;
385  if (banner) {
386  if (banner[0]) {
387  style->attribute("caption", banner);
388  nocap = false;
389  }
390  }
391  if (filter) {
392  if (filter[0]) {
393  style->attribute("filter", "true");
394  style->attribute("filterPattern", filter);
395  }
396  }
397  if (bopen) {
398  if (bopen[0]) {
399  style->attribute("open", bopen);
400  }
401  } else if (type[0] == 'w') {
402  style->attribute("open", "Save");
403  }
404  if (cancel) {
405  if (cancel[0]) {
406  style->attribute("cancel", cancel);
407  }
408  }
409  if (nocap)
410  switch (type[0]) {
411  case 'w':
412  style->attribute("caption", "File write");
413  break;
414  case 'a':
415  style->attribute("caption", "File append");
416  break;
417  case 'r':
418  style->attribute("caption", "File read");
419  break;
420  case 'd':
421  style->attribute("caption", "Directory open");
422  break;
423  case '\0':
424  style->attribute("caption", "File name only");
425  break;
426  }
427  switch (type[0]) {
428  case 'w':
429  chooser_type_ = W;
430  break;
431  case 'a':
432  chooser_type_ = A;
433  break;
434  case 'r':
435  chooser_type_ = R;
436  break;
437  case 'd':
438  chooser_type_ = N;
439  style->attribute("choose_directory", "on");
440  break;
441  case '\0':
442  chooser_type_ = N;
443  break;
444  }
445  fc_ = DialogKit::instance()->file_chooser(path, style);
446  fc_->ref();
447  style->unref();
448 #endif
449 }
450 
451 const char* OcFile::dir() {
452 #if HAVE_IV
453  if (fc_) {
454  dirname_ = *fc_->dir()->string();
455  } else
456 #endif
457  {
458  dirname_ = "";
459  }
460  return dirname_.c_str();
461 }
462 
464 #if HAVE_IV
465  bool accept = false;
466  if (!fc_) {
467  hoc_execerror("First call to file_chooser must at least specify r or w", 0);
468  }
469 
470  Display* d = Session::instance()->default_display();
471  Coord x, y, ax, ay;
472  if (nrn_spec_dialog_pos(x, y)) {
473  ax = 0.0;
474  ay = 0.0;
475  } else {
476  x = d->width() / 2;
477  y = d->height() / 2;
478  ax = 0.5;
479  ay = 0.5;
480  }
481 
482  while (fc_->post_at_aligned(x, y, ax, ay)) {
483  switch (chooser_type_) {
484  case W:
485  if (ok_to_write(*fc_->selected(), NULL)) {
486  open(fc_->selected()->string(), "w");
487  accept = true;
488  }
489  break;
490  case A:
491  if (ok_to_write(*fc_->selected(), NULL)) {
492  open(fc_->selected()->string(), "a");
493  accept = true;
494  }
495  break;
496  case R:
497 #if 1
498  if (ok_to_read(*fc_->selected(), NULL)) {
499  open(fc_->selected()->string(), "r");
500  accept = true;
501  }
502 #else
503  accept = true;
504 #endif
505  break;
506  case N:
507  set_name(fc_->selected()->string());
508  accept = true;
509  }
510  if (accept) {
511  break;
512  }
513  }
514  return accept;
515 #else
516  return false;
517 #endif
518 }
519 
520 
521 // https://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux/29828907#29828907
522 
523 bool isDirExist(const std::string& path) {
524 #if defined(_WIN32)
525  struct _stat info;
526  if (_stat(path.c_str(), &info) != 0) {
527  return false;
528  }
529  return (info.st_mode & _S_IFDIR) != 0;
530 #else
531  struct stat info;
532  if (stat(path.c_str(), &info) != 0) {
533  return false;
534  }
535  return (info.st_mode & S_IFDIR) != 0;
536 #endif
537 }
538 
539 bool makePath(const std::string& path) {
540 #if defined(_WIN32)
541  int ret = _mkdir(path.c_str());
542 #else
543  mode_t mode = 0755;
544  int ret = mkdir(path.c_str(), mode);
545 #endif
546  if (ret == 0)
547  return true;
548 
549  switch (errno) {
550  case ENOENT:
551  // parent didn't exist, try to create it
552  {
553  int pos = path.find_last_of('/');
554  if (pos == std::string::npos)
555 #if defined(_WIN32)
556  pos = path.find_last_of('\\');
557  if (pos == std::string::npos)
558 #endif
559  return false;
560  if (!makePath(path.substr(0, pos)))
561  return false;
562  }
563  // now, try to create again
564 #if defined(_WIN32)
565  return 0 == _mkdir(path.c_str());
566 #else
567  return 0 == mkdir(path.c_str(), mode);
568 #endif
569 
570  case EEXIST:
571  // done!
572  return isDirExist(path);
573 
574  default:
575  return false;
576  }
577 }
#define Style
Definition: _defines.h:278
#define Coord
Definition: _defines.h:17
#define Display
Definition: _defines.h:95
Definition: ocfile.h:7
void flush()
Definition: ocfile.h:26
void close()
Definition: ocfile.cpp:307
std::string dirname_
Definition: ocfile.h:50
bool mktemp()
Definition: ocfile.cpp:358
void set_name(const char *s)
Definition: ocfile.cpp:313
bool eof()
Definition: ocfile.cpp:352
virtual ~OcFile()
Definition: ocfile.cpp:65
FILE * file_
Definition: ocfile.h:51
std::string filename_
Definition: ocfile.h:49
@ R
Definition: ocfile.h:45
@ N
Definition: ocfile.h:45
@ W
Definition: ocfile.h:45
@ A
Definition: ocfile.h:45
void print(const char *s)
Definition: ocfile.h:18
const char * dir()
Definition: ocfile.cpp:451
FILE * file()
Definition: ocfile.cpp:345
OcFile()
Definition: ocfile.cpp:57
bool unlink()
Definition: ocfile.cpp:368
bool file_chooser_popup()
Definition: ocfile.cpp:463
void file_chooser_style(const char *type, const char *path, const char *banner=NULL, const char *filter=NULL, const char *accept=NULL, const char *cancel=NULL)
Definition: ocfile.cpp:373
FileChooser * fc_
Definition: ocfile.h:44
const char * get_name()
Definition: ocfile.h:13
bool open(const char *filename, const char *type)
Definition: ocfile.cpp:335
bool is_open()
Definition: ocfile.h:22
virtual void unref() const
Definition: resource.cpp:47
void class2oc(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
Definition: hoc_oop.cpp:1631
char * gargstr(int narg)
Definition: code2.cpp:227
HocReturnType hoc_return_type_code
Definition: code.cpp:42
#define v
Definition: md1redef.h:11
#define i
Definition: md1redef.h:19
double chkarg(int, double low, double high)
Definition: code2.cpp:626
char buf[512]
Definition: init.cpp:13
std::FILE * hoc_obj_file_arg(int i)
Definition: ocfile.cpp:47
void hoc_assign_str(char **cpp, const char *buf)
Definition: code.cpp:2263
const char * expand_env_var(const char *s)
Definition: fileio.cpp:113
void check_obj_type(Object *obj, const char *type_name)
Definition: hoc_oop.cpp:2098
char ** hoc_temp_charptr(void)
Definition: code.cpp:717
double * hoc_pgetarg(int narg)
Definition: oc_ansi.h:253
void hoc_sprint1(char **ppbuf, int argn)
Definition: fileio.cpp:367
Symbol * hoc_lookup(const char *)
Definition: symbol.cpp:59
char ** hoc_pgargstr(int narg)
Definition: code.cpp:1623
#define TRY_GUI_REDIRECT_METHOD_ACTUAL_DOUBLE(name, sym, v)
Definition: gui-redirect.h:16
char * fgets_unlimited(HocStr *s, NrnFILEWrap *f)
Definition: hoc.cpp:838
HocStr * hoc_tmpbuf
Definition: hoc.cpp:137
static int c
Definition: hoc.cpp:169
int hoc_usegui
Definition: hoc.cpp:121
#define getarg
Definition: hocdec.h:17
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
static char banner[]
Definition: mk_mech.cpp:26
const char * name
Definition: init.cpp:16
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
static List * info
int const size_t const size_t n
Definition: nrngsl.h:10
s
Definition: multisend.cpp:521
int ifarg(int)
Definition: code.cpp:1607
short type
Definition: cabvars.h:10
static double f_printf(void *v)
Definition: ocfile.cpp:103
static double f_scanstr(void *v)
Definition: ocfile.cpp:116
static const char ** f_get_name(void *v)
Definition: ocfile.cpp:168
static double f_chooser(void *v)
Definition: ocfile.cpp:185
static double f_scanvar(void *v)
Definition: ocfile.cpp:111
static double f_is_open(void *v)
Definition: ocfile.cpp:157
static double f_unlink(void *v)
Definition: ocfile.cpp:147
bool makePath(const std::string &path)
Definition: ocfile.cpp:539
static double f_vwrite(void *v)
Definition: ocfile.cpp:228
static double f_close(void *v)
Definition: ocfile.cpp:222
static Symbol * file_class_sym_
Definition: ocfile.cpp:39
char * ivoc_get_temp_file()
Definition: pwman.cpp:3338
static double f_ropen(void *v)
Definition: ocfile.cpp:72
bool isDirExist(const std::string &path)
Definition: ocfile.cpp:523
void OcFile_reg()
Definition: ocfile.cpp:302
static double f_seek(void *v)
Definition: ocfile.cpp:246
static double f_wopen(void *v)
Definition: ocfile.cpp:80
static double f_eof(void *v)
Definition: ocfile.cpp:152
Member_func f_members[]
Definition: ocfile.cpp:278
static void * f_cons(Object *)
Definition: ocfile.cpp:266
static double f_aopen(void *v)
Definition: ocfile.cpp:88
static int ivoc_unlink(const char *)
Definition: ocfile.cpp:42
static double f_tell(void *v)
Definition: ocfile.cpp:260
static const char ** f_dir(void *v)
Definition: ocfile.cpp:178
static double f_flush(void *v)
Definition: ocfile.cpp:162
static void f_destruct(void *v)
Definition: ocfile.cpp:274
static double f_vread(void *v)
Definition: ocfile.cpp:237
static double f_gets(void *v)
Definition: ocfile.cpp:129
static Member_ret_str_func f_retstr_members[]
Definition: ocfile.cpp:298
static double f_mktemp(void *v)
Definition: ocfile.cpp:142
#define BinaryMode(ocfile)
Definition: ocfile.h:61
#define NULL
Definition: spdefs.h:105
double hoc_scan(FILE *)
Definition: fileio.cpp:280
char * buf
Definition: hocstr.h:7
Definition: hocdec.h:173
void * this_pointer
Definition: hocdec.h:178
union Object::@47 u
Definition: model.h:47
bool nrn_spec_dialog_pos(Coord &x, Coord &y)
true if Style 'dialog_spec_position: on' and fills x,y with dialog_left_position and dialog_bottom_po...
bool ok_to_write(const String &, Window *w=NULL)
bool ok_to_read(const String &, Window *w=NULL)