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