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