NEURON
io.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 
3 /* file.mod input routines */
4 #include <stdlib.h>
5 #include <string.h>
6 #include <limits.h>
7 #include <sys/stat.h>
8 #include <errno.h>
9 #include "modl.h"
10 #include <ctype.h>
11 #if MAC && TARGET_API_MAC_CARBON
12 #include <SIOUX.h>
13 #endif
14 #undef METHOD
15 #include "parse1.hpp"
16 #if defined(_WIN32)
17 #include <direct.h>
18 #endif
19 
20 int isend(char*, char*);
21 static void pop_file_stack();
22 static int file_stack_empty();
24 
25 char *inputline()
26 {
27  /* and removes comment, newline, beginning and trailing blanks */
28  /* used to get the TITLE line */
29 #if __TURBOC__ || SYSV || VMS || defined(MINGW)
30 #define index strchr
31 #endif
32  char *cp;
33  int i;
34 
35  buf[0] = '\0';
36  cp = Gets(buf);
37  i = strlen(buf);
38  if (i)
39  buf[i - 1] = '\0';
40  if ((cp = index(buf, '!')) != (char *) 0) {
41  *cp-- = '\0';
42  }
43  while (cp >= buf && isspace(*cp)) {
44  *cp-- = '\0';
45  }
46  /*EMPTY*/
47  for (cp = buf; *cp != '\0' && isspace(*cp); cp++){
48  ;
49  }
50  return stralloc(cp, (char *) 0);
51 }
52 
53 static int linenum = 0;
54 
55 void inblock(char* s)
56 { /* copy input verbatim to intoken up to END*s
57  * error if we get the whole input */
58  char *cp;
59  int l;
60  Item *q;
61 
62  l = linenum;
63  for (;;) {
64  cp = Gets(buf);
65  if (cp == (char *) 0) {
66  linenum = l;
67  diag(s, "block goes to end of file");
68  }
69  if (isend(s, buf)) {
70  break;
71  }
72  q = putintoken(buf, STRING);
73  q->itemtype = VERBATIM;
74  }
75 }
76 
77 int isend(char* s, char* buf)
78 {
79  /* if first chars in buf form a keyword return 1 */
80  char *cp, word[256], *wp, test[256];
81  int yesno = 0;
82 
83  cp = buf;
84  Sprintf(test, "END%s", s);
85  while (*cp == ' ' || *cp == '\t')
86  cp++;
87  if (isalpha(*cp)) {
88  for (wp = word; isalpha(*cp);) {
89  *wp++ = *cp++;
90  }
91  *wp = '\0';
92  if (strcmp(test, word) == 0) {
93  yesno = 1;
94  }
95  }
96  return yesno;
97 }
98 
99 /*
100  * We painfully constuct our own input buffer so that when user errors occur
101  * we can print the whole line. Often, even this is not enough if the error
102  * is at the end of a line. We also count lines so the user can go right to
103  * the error in most cases
104  */
105 static char inlinebuf[2][NRN_BUFSIZE], *inlinep = inlinebuf[0] + 30, *ctp = inlinebuf[0] + 30;
106 static int whichbuf;
107 
108 char* Fgets(char* buf, int size, FILE* f) {
109  char* p = buf;
110  int c, i;
111  for(i=0; i < size; ++ i) {
112  c = getc(f);
113  if (c == EOF || c == 26 || c == 4) { /* ^Z and ^D are end of file */
114  /* some editors don't put a newline at last line */
115  if ( p > buf) {
116  ungetc(c, f);
117  c = '\n';
118  }else{
119  break;
120  }
121  }
122  if (c == '\r') {
123  int c2 = getc(f);
124  if (c2 != '\n') {
125  ungetc(c2, f);
126  }
127  c = '\n';
128  }
129  if (c < 0 || c > 127) {
130  *p++ = '\n';
131  *p='\0';
132  if (!in_comment_) {
133  diag("Non-Ascii character in file:", buf);
134  }
135  lappendstr(filetxtlist, buf);
136  return buf;
137  }
138  *p++ = c;
139  if (c == '\n') {
140  *p = '\0';
141  lappendstr(filetxtlist, buf);
142  return buf;
143  }
144  }
145  if (i >= size) {
146  buf[size-1] = 0;
147  diag("Line too long:", buf);
148  }
149  return (char*)0;
150 }
151 
152 int Getc()
153 {
154  int c;
155  if (ctp == (char *) 0 || *ctp == '\0') {
156  whichbuf = (whichbuf?0:1);
157  inlinep = inlinebuf[whichbuf] + 30;
158  ctp = Fgets(inlinep, 512, fin);
159  if (ctp)
160  linenum++;
161  }
162  if (ctp == (char *) 0) {
163  ctp = inlinep;
164  *ctp = '\0';
165  if (file_stack_empty()) {
166  return EOF;
167  }else{
168  pop_file_stack();
169  return Getc();
170  }
171  }
172  c = *ctp++;
173  return c;
174 }
175 
176 int unGetc(int c)
177 {
178  if (c == EOF)
179  return c;
180  if (ctp > inlinebuf[whichbuf]) {
181  ctp--;
182  *ctp = c;
183  } else {
184  diag("internal error in unGetc", "");
185  }
186  return c;
187 }
188 
189 char *Gets(char* buf)
190 {
191  char *cp;
192  int c;
193 
194  cp = buf;
195  while ((c = Getc()) != EOF && c != '\n') {
196  *cp++ = c;
197  }
198  if (c == '\n') {
199  *cp++ = c;
200  *cp++ = '\0';
201  return buf;
202  } else if (c == EOF) {
203  return (char *) 0;
204  } else {
205  diag("internal error in Gets()", "");
206  }
207  return (char *) 0;
208 }
209 
210 #if 0 /* not currently used */
211 void unGets(char* buf) /* all this because we don't have an ENDBLOCK
212  * keyword */
213 {
214  if (ctp != '\0') { /* can only be called after successful Gets */
215  Strcpy(inlinep, buf);
216  ctp = inlinep;
217  } else {
218  diag("internal error in unGets()", "");
219  }
220 }
221 #endif
222 
223 char* current_line() { /* assumes we actually want the previous line */
224  static char buf[NRN_BUFSIZE];
225  char* p;
226  sprintf(buf,"at line %d in file %s:\\n%s", linenum-1, finname,
227  inlinebuf[whichbuf?0:1]+30);
228  for (p = buf; *p; ++p) {
229  if (*p == '\n') {
230  *p = '\0';
231  }
232  if (*p == '"') {
233  *p = '\047';
234  }
235  }
236  return buf;
237 }
238 
239 /* two arguments so we can pass a name to construct an error message. */
240 void diag(char* s1, char* s2)
241 {
242  char *cp;
243  Fprintf(stderr, "%s", s1);
244  if (s2) {
245  Fprintf(stderr, "%s", s2);
246  }
247  if (fin) {
248  Fprintf(stderr, " at line %d in file %s\n", linenum, finname);
249  Fprintf(stderr, "%s", inlinep);
250  if (ctp >= inlinep) {
251  for (cp = inlinep; cp < ctp - 1; cp++) {
252  if (*cp == '\t') {
253  Fprintf(stderr, "\t");
254  } else {
255  Fprintf(stderr, " ");
256  }
257  }
258  Fprintf(stderr, "^");
259  }
260  }
261  Fprintf(stderr, "\n");
262 #if MAC && TARGET_API_MAC_CARBON
263  SIOUXSettings.autocloseonquit = true;
264  RunApplicationEventLoop();
265 #endif
266  exit(1);
267 }
268 
269 #if 0
270 static Symbol *symq[20], **symhead = symq, **symtail = symq;
271 
272 /*
273  * the following is a nonsensical implementation of heirarchical model
274  * building. Disregard. It assumes .mod files can be concatenated to produce
275  * meaningful models. It was this insanity which prompted us to allow use of
276  * variables before declaration
277  */
278 void enquextern(Symbol* sym)
279 {
280  *symtail++ = sym;
281 }
282 
283 FILE *dequextern()
284 {
285  char fname[256];
286  FILE *f;
287  Symbol *s;
288 
289  if (symhead >= symtail)
290  return (FILE *) 0;
291  s = *symhead++;
292  Sprintf(fname, "%s.mod", s->name);
293  f = fopen(fname, "r");
294  if (f == (FILE *) 0) {
295  diag("Can't open", fname);
296  }
297  Fclose(fin);
298  linenum = 0;
299  Strcpy(finname, fname);
300  return f;
301 }
302 #endif
303 
304 typedef struct FileStackItem {
305  char* inlinep;
306  char* ctp;
307  int linenum;
308  FILE* fp;
309  char finname[NRN_BUFSIZE];
310 } FileStackItem;
311 
312 static List* filestack;
313 
314 static int getprefix(char* prefix, char* s)
315 {
316  char* cp;
317  strcpy(prefix, s);
318  for (cp = prefix + strlen(prefix); cp+1 != prefix; --cp) {
319  if (*cp == '/') {
320  break;
321  }
322  *cp = '\0';
323  }
324  return (prefix[0] != '\0');
325 }
326 
327 static FILE* include_open(char* fname, int err)
328 {
329  FILE* f = (FILE*)0;
330  FileStackItem* fsi;
331  char* dirs, *colon;
332  /* since dirs is a ':' separated list of paths, there is no
333  limit to the size and so allocate from size of dirs and free
334  */
335  char *buf, *buf2;
336  if(fname[0] == '/') { /* highest precedence is complete filename */
337  return fopen(fname, "r");
338  }
339 
340  fsi = (FileStackItem*)(SYM(filestack->prev));
341  buf = static_cast<char *>(emalloc(NRN_BUFSIZE));
342  if (getprefix(buf, fsi->finname)) {
343  strcat(buf, fname);
344  f = fopen(buf, "r"); /* first try in directory of last file */
345  if (f) {
346  strcpy(fname, buf);
347  free(buf);
348  return f;
349  }
350  if (err) fprintf(stderr, "Couldn't open: %s\n", buf);
351  }
352  f = fopen(fname, "r"); /* next try current working directory */
353  if (f) {
354  free(buf);
355  return f;
356  }
357  sprintf(buf, "../%s", fname); /* Next try next dir up. */
358  if ((f = fopen(buf, "r")) != NULL) {
359  strcpy(fname, buf);
360  free(buf);
361  return f;
362  }
363 
364  if (err) fprintf(stderr, "Couldn't open: %s\n", fname);
365  /* try all the directories in the environment variable */
366  /* a colon separated list of directories */
367  dirs = getenv("MODL_INCLUDE");
368  if (dirs) {
369  buf = stralloc(dirs, buf); /* frees old buf and allocates */
370  dirs = buf;
371  colon = dirs;
372  for (dirs = colon; *dirs; dirs = colon){
373  buf2 = NULL;
374  for(; *colon; ++colon) {
375  if (*colon == ':') {
376  *colon = '\0';
377  ++colon;
378  break;
379  }
380  }
381  buf2 = static_cast<char *>(emalloc(strlen(dirs) + 2 + strlen(fname)));
382  strcpy(buf2, dirs);
383  strcat(buf2, "/");
384  strcat(buf2, fname);
385  f = fopen(buf2, "r");
386  if (f) {
387  strcpy(fname, buf2);
388  free(buf);
389  free(buf2);
390  return f;
391  }
392  if (err) fprintf(stderr, "Couldn't open: %s\n", buf2);
393  free(buf2);
394  }
395  free(buf);
396  }
397  return f;
398 }
399 
401 {
402  char* pf = NULL;
403  char fname[NRN_BUFSIZE];
404  Item* qinc;
405  FileStackItem* fsi;
406  if (!filestack) {
407  filestack = newlist();
408  }
409  strcpy(fname, STR(q) + 1);
410  fname[strlen(fname)-1] = '\0';
411  fsi = (FileStackItem*)emalloc(sizeof(FileStackItem));
412  lappendsym(filestack, (Symbol*)fsi);
413 
414  fsi->inlinep = inlinep;
415  fsi->ctp = ctp;
416  fsi->linenum = linenum;
417  fsi->fp = fin;
418  strcpy(fsi->finname, finname);
419 
420  strcpy(finname, fname);
421  if ((fin = include_open(fname, 0)) == (FILE*)0) {
422  include_open(fname, 1);
423  diag("Couldn't open ", fname);
424  }
425  fprintf(stderr, "INCLUDEing %s\n", fname);
426  ctp = (char*)0;
427  linenum = 0;
428 
429  qinc = filetxtlist->prev;
430  sprintf(buf, ":::%s", STR(qinc));
431  replacstr(qinc, buf);
432 #if HAVE_REALPATH
433  pf = realpath(fname, NULL);
434 #endif
435  if (pf) {
436  sprintf(buf, ":::realpath %s\n", pf);
437  free(pf);
439  }
440 }
441 
442 static void pop_file_stack() {
443  sprintf(buf, ":::end INCLUDE %s\n", finname);
445  FileStackItem* fsi;
446  fsi = (FileStackItem*)(SYM(filestack->prev));
447  remove(filestack->prev);
448  linenum = fsi->linenum;
449  inlinep = fsi->inlinep;
450  fclose(fin);
451  fin = fsi->fp;
452  strcpy(finname, fsi->finname);
453  free(fsi);
454 }
455 
456 static int file_stack_empty() {
457  if (!filestack) {
458  return 1;
459  }
460  return (filestack->next == filestack);
461 }
462 
463 /* adapted from : gist@jonathonreinhart/mkdir_p.c */
464 int mkdir_p(const char *path)
465 {
466  const size_t len = strlen(path);
467  char mypath[PATH_MAX];
468  char *p;
469 
470  errno = 0;
471 
472  /* copy string so its mutable */
473  if (len > sizeof(mypath)-1) {
474  fprintf(stderr, "Output directory path too long\n");
475  return -1;
476  }
477 
478  strcpy(mypath, path);
479 
480  /* iterate the string */
481  for (p = mypath + 1; *p; p++) {
482  if (*p == '/') {
483  /* temporarily truncate */
484  *p = '\0';
485 
486 #if defined(_WIN32)
487  if (_mkdir(mypath) != 0) {
488 #else
489  if (mkdir(mypath, S_IRWXU) != 0) {
490 #endif
491  if (errno != EEXIST)
492  return -1;
493  }
494  *p = '/';
495  }
496  }
497 
498 #if defined(_WIN32)
499  if (_mkdir(mypath) != 0) {
500 #else
501  if (mkdir(mypath, S_IRWXU) != 0) {
502 #endif
503  if (errno != EEXIST)
504  return -1;
505  }
506 
507  return 0;
508 }
509 
static char * ctp
Definition: io.cpp:105
char * stralloc(char *buf, char *rel)
Definition: list.cpp:208
short itemtype
Definition: model.h:16
int Getc()
Definition: io.cpp:61
char * current_line()
Definition: io.cpp:223
List * filetxtlist
Definition: modl.cpp:68
int in_comment_
Definition: io.cpp:23
char finname[NRN_BUFSIZE]
Definition: model.cpp:38
int mkdir_p(const char *path)
Definition: io.cpp:464
char * Fgets(char *buf, int size, FILE *f)
Definition: io.cpp:26
static List * filestack
Definition: io.cpp:312
char finname[NRN_BUFSIZE]
Definition: io.cpp:233
#define SYM(q)
Definition: model.h:86
size_t p
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:161
static int file_stack_empty()
Definition: io.cpp:456
char * name
Definition: model.h:72
#define NRN_BUFSIZE
Definition: model.h:13
struct Item * prev
Definition: model.h:20
#define Fprintf
Definition: model.h:249
void pop_file_stack()
Definition: io.cpp:337
static int whichbuf
Definition: io.cpp:106
struct Item * next
Definition: model.h:19
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
Definition: model.h:15
FILE * fp
Definition: io.cpp:232
char * ctp
Definition: io.cpp:230
static int getprefix(char *prefix, char *s)
Definition: io.cpp:314
static struct prefix prefix[]
_CONST char * s
Definition: system.cpp:74
#define fin
Definition: redef.h:60
char * Gets(char *buf)
Definition: io.cpp:97
Item * lappendstr(List *list, char *str)
Definition: list.cpp:149
void unGets(char *)
static const char * fname(const char *name)
Definition: nrnbbs.cpp:108
#define STRING
Definition: bbslsrv.cpp:9
static int linenum
Definition: io.cpp:53
void enquextern(Symbol *)
void inblock(char *s)
Definition: io.cpp:55
errno
Definition: system.cpp:98
char * getenv(const char *s)
Definition: macprt.cpp:67
fprintf(stderr, "Don't know the location of params at %p\, pp)
Definition: model.h:57
#define Fclose
Definition: model.h:250
char * emalloc(unsigned n)
Definition: list.cpp:189
List * newlist()
Definition: list.cpp:50
#define Strcpy
Definition: model.h:253
static char inlinebuf[2][NRN_BUFSIZE]
Definition: io.cpp:105
NMODL parser global flags / functions.
int isend(char *, char *)
Definition: io.cpp:77
struct FileStackItem FileStackItem
void diag(char *s1, char *s2)
Definition: io.cpp:119
#define STR(q)
Definition: model.h:87
#define i
Definition: md1redef.h:12
#define c
static char * inlinep
Definition: io.cpp:105
char * inputline()
Definition: io.cpp:25
char buf[512]
Definition: init.cpp:13
Item * putintoken(char *s, short type, short toktype)
Definition: list.cpp:258
void replacstr(Item *q, char *s)
Definition: list.cpp:250
#define Sprintf
Definition: model.h:248
static FILE * include_open(char *fname, int err)
Definition: io.cpp:327
size_t q
#define PATH_MAX
Definition: limits.h:64
FILE * fopen()
char * inlinep
Definition: io.cpp:229
return NULL
Definition: cabcode.cpp:461
void include_file(Item *q)
Definition: io.cpp:309
short index
Definition: cabvars.h:11
int unGetc(int c)
Definition: io.cpp:83
int linenum
Definition: io.cpp:231