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  char format[32];
121  snprintf(format, sizeof(format), "%%%zus", hoc_tmpbuf->size - 1);
122  int i = fscanf(f->file(), format, buf);
123  if (i == 1) {
124  hoc_assign_str(pbuf, buf);
125  return double(strlen(buf));
126  } else {
127  return -1.;
128  }
129 }
130 
131 static double f_gets(void* v) {
132  OcFile* f = (OcFile*) v;
133  char** pbuf = hoc_pgargstr(1);
134  char* buf;
135  FILE* fw = f->file();
136  if ((buf = fgets_unlimited(hoc_tmpbuf, fw)) != 0) {
137  hoc_assign_str(pbuf, buf);
138  return double(strlen(buf));
139  } else {
140  return -1.;
141  }
142 }
143 
144 static double f_mktemp(void* v) {
145  OcFile* f = (OcFile*) v;
146  return double(f->mktemp());
147 }
148 
149 static double f_unlink(void* v) {
150  OcFile* f = (OcFile*) v;
151  return double(f->unlink());
152 }
153 
154 static double f_eof(void* v) {
155  OcFile* f = (OcFile*) v;
156  return double(f->eof());
157 }
158 
159 static double f_is_open(void* v) {
160  OcFile* f = (OcFile*) v;
161  return double(f->is_open());
162 }
163 
164 static double f_flush(void* v) {
165  OcFile* f = (OcFile*) v;
166  f->flush();
167  return 1;
168 }
169 
170 static const char** f_get_name(void* v) {
171  OcFile* f = (OcFile*) v;
172  char** ps = hoc_temp_charptr();
173  *ps = (char*) f->get_name();
174  if (ifarg(1)) {
175  hoc_assign_str(hoc_pgargstr(1), *ps);
176  }
177  return (const char**) ps;
178 }
179 
180 static const char** f_dir(void* v) {
181  char** ps = hoc_temp_charptr();
182  OcFile* f = (OcFile*) v;
183  *ps = (char*) f->dir();
184  return (const char**) ps;
185 }
186 
187 static double f_chooser(void* v) {
189 #if HAVE_IV
190  if (hoc_usegui) {
191  OcFile* f = (OcFile*) v;
192  f->close();
193 
194  if (!ifarg(1)) {
195  return double(f->file_chooser_popup());
196  }
197 
198  char *type, *banner, *filter, *bopen, *cancel;
199  banner = filter = bopen = cancel = NULL;
200  const char* path = ".";
201  type = gargstr(1);
202  if (ifarg(2)) {
203  banner = gargstr(2);
204  }
205  if (ifarg(3)) {
206  filter = gargstr(3);
207  }
208  if (ifarg(4)) {
209  bopen = gargstr(4);
210  }
211  if (ifarg(5)) {
212  cancel = gargstr(5);
213  }
214  if (ifarg(6)) {
215  path = gargstr(6);
216  }
217 
218  f->file_chooser_style(type, path, banner, filter, bopen, cancel);
219  }
220 #endif
221  return 1.;
222 }
223 
224 static double f_close(void* v) {
225  OcFile* f = (OcFile*) v;
226  f->close();
227  return 0.;
228 }
229 
230 static double f_vwrite(void* v) {
231  OcFile* f = (OcFile*) v;
232  size_t n = 1;
233  if (ifarg(2))
234  n = long(chkarg(1, 1., 2.e18));
235  const char* x = (const char*) hoc_pgetarg(ifarg(2) + 1);
236  BinaryMode(f) return (double) fwrite(x, sizeof(double), n, f->file());
237 }
238 
239 static double f_vread(void* v) {
240  OcFile* f = (OcFile*) v;
241  size_t n = 1;
242  if (ifarg(2))
243  n = int(chkarg(1, 1., 2.e18));
244  char* x = (char*) hoc_pgetarg(ifarg(2) + 1);
245  BinaryMode(f) return (double) fread(x, sizeof(double), n, f->file());
246 }
247 
248 static double f_seek(void* v) {
249  OcFile* f = (OcFile*) v;
250  long n = 0;
251  int base = 0;
252  if (ifarg(1)) {
253  // no longer check since since many machines have >2GB files
254  n = long(*getarg(1));
255  }
256  if (ifarg(2)) {
257  base = int(chkarg(2, 0., 2.));
258  }
259  BinaryMode(f) return (double) fseek(f->file(), n, base);
260 }
261 
262 static double f_tell(void* v) {
263  OcFile* f = (OcFile*) v;
265  BinaryMode(f) return (double) ftell(f->file());
266 }
267 
268 static void* f_cons(Object*) {
269  OcFile* f = new OcFile();
270  if (ifarg(1)) {
271  f->set_name(gargstr(1));
272  }
273  return f;
274 }
275 
276 static void f_destruct(void* v) {
277  delete (OcFile*) v;
278 }
279 
280 Member_func f_members[] = {{"ropen", f_ropen},
281  {"wopen", f_wopen},
282  {"aopen", f_aopen},
283  {"printf", f_printf},
284  {"scanvar", f_scanvar},
285  {"scanstr", f_scanstr},
286  {"gets", f_gets},
287  {"eof", f_eof},
288  {"isopen", f_is_open},
289  {"chooser", f_chooser},
290  {"close", f_close},
291  {"vwrite", f_vwrite},
292  {"vread", f_vread},
293  {"seek", f_seek},
294  {"tell", f_tell},
295  {"mktemp", f_mktemp},
296  {"unlink", f_unlink},
297  {"flush", f_flush},
298  {nullptr, nullptr}};
299 
301  {"dir", f_dir},
302  {nullptr, nullptr}};
303 
304 void OcFile_reg() {
305  class2oc("File", f_cons, f_destruct, f_members, nullptr, f_retstr_members);
306  file_class_sym_ = hoc_lookup("File");
307 }
308 
310  if (file_) {
311  fclose(file_);
312  }
313  file_ = NULL;
314 }
315 void OcFile::set_name(const char* s) {
316  close();
317  if (s != filename_.c_str()) {
318  filename_ = s;
319  }
320 }
321 
322 #ifdef WIN32
323 void OcFile::binary_mode() {
324  if (file() && !binary_) {
325  if (ftell(file()) != 0) {
327  ":can switch to dos binary file mode only at beginning of file.\n\
328  Use File.seek(0) after opening or use a binary style read/write as first\n\
329  access to file.");
330  }
331  setmode(fileno(file()), O_BINARY);
332  binary_ = true;
333  }
334 }
335 #endif
336 
337 bool OcFile::open(const char* name, const char* type) {
338  set_name(name);
339 #ifdef WIN32
340  binary_ = false;
341  strcpy(mode_, type);
342 #endif
343  file_ = fopen(expand_env_var(name), type);
344  return is_open();
345 }
346 
347 FILE* OcFile::file() {
348  if (!file_) {
349  hoc_execerror(get_name(), ":file is not open");
350  }
351  return file_;
352 }
353 
354 bool OcFile::eof() {
355  int c;
356  c = getc(file());
357  return ungetc(c, file()) == EOF;
358 }
359 
361  char* s = ivoc_get_temp_file();
362  if (s) {
363  set_name(s);
364  delete[] s;
365  return true;
366  }
367  return false;
368 }
369 
371  int i = ivoc_unlink(get_name());
372  return i == 0;
373 }
374 
376  const char* path,
377  const char* banner,
378  const char* filter,
379  const char* bopen,
380  const char* cancel) {
381 #if HAVE_IV
383 
384  Style* style = new Style(Session::instance()->style());
385  style->ref();
386  bool nocap = true;
387  if (banner) {
388  if (banner[0]) {
389  style->attribute("caption", banner);
390  nocap = false;
391  }
392  }
393  if (filter) {
394  if (filter[0]) {
395  style->attribute("filter", "true");
396  style->attribute("filterPattern", filter);
397  }
398  }
399  if (bopen) {
400  if (bopen[0]) {
401  style->attribute("open", bopen);
402  }
403  } else if (type[0] == 'w') {
404  style->attribute("open", "Save");
405  }
406  if (cancel) {
407  if (cancel[0]) {
408  style->attribute("cancel", cancel);
409  }
410  }
411  if (nocap)
412  switch (type[0]) {
413  case 'w':
414  style->attribute("caption", "File write");
415  break;
416  case 'a':
417  style->attribute("caption", "File append");
418  break;
419  case 'r':
420  style->attribute("caption", "File read");
421  break;
422  case 'd':
423  style->attribute("caption", "Directory open");
424  break;
425  case '\0':
426  style->attribute("caption", "File name only");
427  break;
428  }
429  switch (type[0]) {
430  case 'w':
431  chooser_type_ = W;
432  break;
433  case 'a':
434  chooser_type_ = A;
435  break;
436  case 'r':
437  chooser_type_ = R;
438  break;
439  case 'd':
440  chooser_type_ = N;
441  style->attribute("choose_directory", "on");
442  break;
443  case '\0':
444  chooser_type_ = N;
445  break;
446  }
447  fc_ = DialogKit::instance()->file_chooser(path, style);
448  fc_->ref();
449  style->unref();
450 #endif
451 }
452 
453 const char* OcFile::dir() {
454 #if HAVE_IV
455  if (fc_) {
456  dirname_ = fc_->dir()->string();
457  } else
458 #endif
459  {
460  dirname_ = "";
461  }
462  return dirname_.c_str();
463 }
464 
466 #if HAVE_IV
467  bool accept = false;
468  if (!fc_) {
469  hoc_execerror("First call to file_chooser must at least specify r or w", 0);
470  }
471 
472  Display* d = Session::instance()->default_display();
473  Coord x, y, ax, ay;
474  if (nrn_spec_dialog_pos(x, y)) {
475  ax = 0.0;
476  ay = 0.0;
477  } else {
478  x = d->width() / 2;
479  y = d->height() / 2;
480  ax = 0.5;
481  ay = 0.5;
482  }
483 
484  while (fc_->post_at_aligned(x, y, ax, ay)) {
485  switch (chooser_type_) {
486  case W:
487  if (ok_to_write(*fc_->selected(), NULL)) {
488  open(fc_->selected()->string(), "w");
489  accept = true;
490  }
491  break;
492  case A:
493  if (ok_to_write(*fc_->selected(), NULL)) {
494  open(fc_->selected()->string(), "a");
495  accept = true;
496  }
497  break;
498  case R:
499 #if 1
500  if (ok_to_read(*fc_->selected(), NULL)) {
501  open(fc_->selected()->string(), "r");
502  accept = true;
503  }
504 #else
505  accept = true;
506 #endif
507  break;
508  case N:
509  set_name(fc_->selected()->string());
510  accept = true;
511  }
512  if (accept) {
513  break;
514  }
515  }
516  return accept;
517 #else
518  return false;
519 #endif
520 }
521 
522 
523 // https://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux/29828907#29828907
524 
525 bool isDirExist(const std::string& path) {
526 #if defined(_WIN32)
527  struct _stat info;
528  if (_stat(path.c_str(), &info) != 0) {
529  return false;
530  }
531  return (info.st_mode & _S_IFDIR) != 0;
532 #else
533  struct stat info;
534  if (stat(path.c_str(), &info) != 0) {
535  return false;
536  }
537  return (info.st_mode & S_IFDIR) != 0;
538 #endif
539 }
540 
541 bool makePath(const std::string& path) {
542 #if defined(_WIN32)
543  int ret = _mkdir(path.c_str());
544 #else
545  mode_t mode = 0755;
546  int ret = mkdir(path.c_str(), mode);
547 #endif
548  if (ret == 0)
549  return true;
550 
551  switch (errno) {
552  case ENOENT:
553  // parent didn't exist, try to create it
554  {
555  int pos = path.find_last_of('/');
556  if (pos == std::string::npos)
557 #if defined(_WIN32)
558  pos = path.find_last_of('\\');
559  if (pos == std::string::npos)
560 #endif
561  return false;
562  if (!makePath(path.substr(0, pos)))
563  return false;
564  }
565  // now, try to create again
566 #if defined(_WIN32)
567  return 0 == _mkdir(path.c_str());
568 #else
569  return 0 == mkdir(path.c_str(), mode);
570 #endif
571 
572  case EEXIST:
573  // done!
574  return isDirExist(path);
575 
576  default:
577  return false;
578  }
579 }
#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:309
std::string dirname_
Definition: ocfile.h:50
bool mktemp()
Definition: ocfile.cpp:360
void set_name(const char *s)
Definition: ocfile.cpp:315
bool eof()
Definition: ocfile.cpp:354
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:453
FILE * file()
Definition: ocfile.cpp:347
OcFile()
Definition: ocfile.cpp:57
bool unlink()
Definition: ocfile.cpp:370
bool file_chooser_popup()
Definition: ocfile.cpp:465
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:375
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:337
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:369
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:170
static double f_chooser(void *v)
Definition: ocfile.cpp:187
static double f_scanvar(void *v)
Definition: ocfile.cpp:111
static double f_is_open(void *v)
Definition: ocfile.cpp:159
static double f_unlink(void *v)
Definition: ocfile.cpp:149
bool makePath(const std::string &path)
Definition: ocfile.cpp:541
static double f_vwrite(void *v)
Definition: ocfile.cpp:230
static double f_close(void *v)
Definition: ocfile.cpp:224
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:525
void OcFile_reg()
Definition: ocfile.cpp:304
static double f_seek(void *v)
Definition: ocfile.cpp:248
static double f_wopen(void *v)
Definition: ocfile.cpp:80
static double f_eof(void *v)
Definition: ocfile.cpp:154
Member_func f_members[]
Definition: ocfile.cpp:280
static void * f_cons(Object *)
Definition: ocfile.cpp:268
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:262
static const char ** f_dir(void *v)
Definition: ocfile.cpp:180
static double f_flush(void *v)
Definition: ocfile.cpp:164
static void f_destruct(void *v)
Definition: ocfile.cpp:276
static double f_vread(void *v)
Definition: ocfile.cpp:239
static double f_gets(void *v)
Definition: ocfile.cpp:131
static Member_ret_str_func f_retstr_members[]
Definition: ocfile.cpp:300
static double f_mktemp(void *v)
Definition: ocfile.cpp:144
#define BinaryMode(ocfile)
Definition: ocfile.h:61
#define NULL
Definition: spdefs.h:105
double hoc_scan(FILE *)
Definition: fileio.cpp:280
size_t size
Definition: hocstr.h:8
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)