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