MBDyn-1.7.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
parsinc.cc
Go to the documentation of this file.
1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/libraries/libmbutil/parsinc.cc,v 1.59 2017/01/12 14:44:05 masarati Exp $ */
2 /*
3  * MBDyn (C) is a multibody analysis code.
4  * http://www.mbdyn.org
5  *
6  * Copyright (C) 1996-2017
7  *
8  * Pierangelo Masarati <masarati@aero.polimi.it>
9  * Paolo Mantegazza <mantegazza@aero.polimi.it>
10  *
11  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
12  * via La Masa, 34 - 20156 Milano, Italy
13  * http://www.aero.polimi.it
14  *
15  * Changing this copyright notice is forbidden.
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation (version 2 of the License).
20  *
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */
31 
32 /* parser con include */
33 
34 #include "mbconfig.h" /* This goes first in every *.c,*.cc file */
35 
36 #include <cstring>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #ifdef HAVE_PWD_H
41 #include <pwd.h>
42 #endif /* HAVE_PWD_H */
43 #include <errno.h>
44 
45 #include "parsinc.h"
46 #include "filename.h"
47 
48 #ifndef PATH_MAX
49 #define PATH_MAX 4096
50 #endif // !PATH_MAX
51 
52 
53 
54 struct IncludeDR : public DescRead {
55  bool Read(HighParser& HP);
56 };
57 
58 bool
60 {
61  IncludeParser *pIP = dynamic_cast<IncludeParser *>(&HP);
62  ASSERT(pIP != 0);
63  return pIP->Include_int();
64 }
65 
66 struct ChDirDR : public DescRead {
67  bool Read(HighParser& HP);
68 };
69 
70 bool
72 {
73  if (!HP.IsArg()) {
74  silent_cerr("Parser error "
75  "in ChDir::Read(), "
76  "colon expected at line " << HP.GetLineData()
77  << std::endl);
79  }
80 
81  IncludeParser *pIP = dynamic_cast<IncludeParser *>(&HP);
82  ASSERT(pIP != 0);
83 
84  const char* sfname = pIP->GetFileName();
85 
86  if (chdir(sfname)) {
87  silent_cerr("Error in chdir, path=\"" << sfname << "\" at line "
88  << HP.GetLineData() << std::endl);
90  }
91 
92  return true;
93 }
94 
95 static unsigned desc_done;
96 
97 static void
99 {
100  // NOTE: data will be destroyed when the underlying HighParser is destroyed (is this what we want?)
101  if (::desc_done++ > 0) {
102  return;
103  }
104 
105  SetDescData("include", new IncludeDR);
106  SetDescData("chdir", new ChDirDR);
107 
108  /* NOTE: add here initialization of new built-in descriptions;
109  * alternative ways to register new custom descriptions are:
110  * - call SetDescData() from anywhere in the code
111  * - write a module that calls SetDescData() from inside a function
112  * called module_init(), and run-time load it using "module load"
113  * in the input file.
114  */
115 }
116 
117 
118 /* IncludeParser - begin */
119 
121  InputStream& streamIn,
122  const char *sInitialFile)
123 : HighParser(MP, streamIn),
124 sCurrPath(NULL),
125 sInitialPath(NULL),
126 sCurrFile(NULL)
127 {
128  ASSERT(sInitialFile != NULL);
129 #ifdef USE_INCLUDE_PARSER
130  char s[PATH_MAX];
131  if (getcwd(s, sizeof(s)) == NULL) {
132  silent_cerr("Error in getcwd()" << std::endl);
134  }
135  SAFESTRDUP(sCurrPath, s);
137  DEBUGCOUT("Current directory is \"" << sCurrPath << "\"" << std::endl);
138 
139  SAFESTRDUP(sCurrFile, sInitialFile);
140 #else /* !USE_INCLUDE_PARSER */
141  NO_OP;
142 #endif /* !USE_INCLUDE_PARSER */
143 
144  // NOTE: data will be destroyed when the underlying HighParser is destroyed (is this what we want?)
145  InitDescData();
146 }
147 
148 
150 {
152 }
153 
154 
156 {
157  MyInput* pmi = NULL;
158  if (!myinput.empty()) {
159  pmi = myinput.top();
160  ASSERT(pmi != NULL);
161  /* Nota: deve esserci solo l'ultimo file */
162  ASSERT(pf != NULL);
163  ASSERT(pIn != NULL);
164 
165 #ifdef USE_INCLUDE_PARSER
166  ASSERT(sCurrPath != NULL);
167  ASSERT(sCurrFile != NULL);
168 #endif /* USE_INCLUDE_PARSER */
169 
170  if (pf != NULL) {
171  SAFEDELETE(pf);
172  }
173  if (pIn != NULL) {
174  SAFEDELETE(pIn);
175  }
176 
177 #ifdef USE_INCLUDE_PARSER
178  DEBUGCOUT("Leaving directory <" << sCurrPath
179  << ">, file <" << sCurrFile << '>' << std::endl);
180  if (sCurrPath != NULL) {
182  sCurrPath = NULL;
183  }
184  if (sCurrFile != NULL) {
186  sCurrFile = NULL;
187  }
188 #endif /* USE_INCLUDE_PARSER */
189 
190  pf = pmi->pfile;
191  pIn = pmi->pis;
192 
193 #ifdef USE_INCLUDE_PARSER
194  sCurrPath = pmi->sPath;
195  sCurrFile = pmi->sFile;
196  DEBUGCOUT("Entering directory \"" << sCurrPath
197  << "\", file \"" << sCurrFile << "\"" << std::endl);
198  if (chdir(sCurrPath)) {
199  silent_cerr("Error in chdir, path=\""
200  << sCurrPath << "\"" << std::endl);
202  }
203 #endif /* USE_INCLUDE_PARSER */
204 
205  /* pmi must be non NULL */
206  SAFEDELETE(pmi);
207 
208  myinput.pop();
209  }
210 
211  /* sCurrPath can be NULL if Close() has been already called */
212 #ifdef USE_INCLUDE_PARSER
213  if (sCurrPath != NULL) {
215  sCurrPath = NULL;
216  }
217  if (sCurrFile != NULL) {
219  sCurrFile = NULL;
220  }
221 #endif /* USE_INCLUDE_PARSER */
222 }
223 
224 flag
226 {
227  MyInput* pmi = NULL;
228  if (!myinput.empty()) {
229  pmi = myinput.top();
230 
231  ASSERT(pmi != NULL);
232  /*
233  * Nota: se la stack e' piena, allora sia pf che pIn
234  * devono essere diversi da NULL; viceversa, se la stack
235  * e' vuota, pf deve essere NULL.
236  */
237  ASSERT(pf != NULL);
238  ASSERT(pIn != NULL);
239 #ifdef USE_INCLUDE_PARSER
240  ASSERT(sCurrPath != NULL);
241  ASSERT(sCurrFile != NULL);
242 #endif /* USE_INCLUDE_PARSER */
243 
244  SAFEDELETE(pf);
245  SAFEDELETE(pIn);
246 #ifdef USE_INCLUDE_PARSER
247  DEBUGCOUT("Leaving directory <" << sCurrPath
248  << ">, file <" << sCurrFile << '>' << std::endl);
250  sCurrPath = NULL;
252  sCurrFile = NULL;
253 #endif /* USE_INCLUDE_PARSER */
254 
255  pf = pmi->pfile;
256  pIn = pmi->pis;
257 #ifdef USE_INCLUDE_PARSER
258  sCurrPath = pmi->sPath;
259  sCurrFile = pmi->sFile;
260  DEBUGCOUT("Entering directory \"" << sCurrPath
261  << "\", file \"" << sCurrFile << "\"" << std::endl);
262  if (chdir(sCurrPath)) {
263  silent_cerr("Error in chdir, path=\""
264  << sCurrPath << "\"" << std::endl);
266  }
267 #endif /* USE_INCLUDE_PARSER */
268 
269  SAFEDELETE(pmi);
270 
271  myinput.pop();
272 
273  return flag(1);
274 
275  } else {
276  return flag(0);
277  }
278 }
279 
280 bool
282 {
283  // if (FirstToken() == UNKNOWN) {
284  if (!IsArg()) {
285  silent_cerr("Parser error in IncludeParser::Include_int(),"
286  " colon expected at line " << GetLineData()
287  << std::endl);
289  }
290 
291  const char* sfname = GetFileName();
292 
293  if (sfname != 0) {
294  struct stat s;
295 
296  if (stat(sfname, &s)) {
297  int save_errno = errno;
298 
299  silent_cerr("Cannot stat file <" << sfname << "> "
300  "at line " << GetLineData() << ": "
301  << save_errno
302  << " (" << strerror(save_errno) << ")"
303  << std::endl);
304  throw ErrFile(MBDYN_EXCEPT_ARGS);
305  }
306 
307  if (!S_ISREG(s.st_mode)) {
308  silent_cerr("File <" << sfname << "> "
309  "at line " << GetLineData() << ": "
310  "not a regular file?" << std::endl);
311  throw ErrFile(MBDYN_EXCEPT_ARGS);
312  }
313 
314  if (!(s.st_mode & S_IRUSR)) {
315  silent_cerr("File <" << sfname << "> "
316  "at line " << GetLineData() << ": "
317  "no read permissions?" << std::endl);
318  throw ErrFile(MBDYN_EXCEPT_ARGS);
319  }
320  }
321 
322  std::ifstream *pf_old = pf;
323  InputStream *pIn_old = pIn;
324  char *sOldPath = sCurrPath;
325  char *sOldFile = sCurrFile;
326 
327  pf = NULL;
328  pIn = NULL;
329 
330 #ifdef _WIN32
331  // open the file in non translated mode in order not to break seek operations
332  SAFENEWWITHCONSTRUCTOR(pf, std::ifstream, std::ifstream(sfname, std::ios::binary));
333 #else
334  SAFENEWWITHCONSTRUCTOR(pf, std::ifstream, std::ifstream(sfname));
335 #endif
336  if (!(*pf)) {
337 #ifdef DEBUG
338  char *buf = getcwd(NULL, 0);
339  if (buf != NULL) {
340  DEBUGCERR("Current directory \"" << buf << "\""
341  << std::endl);
342  free(buf);
343  }
344 #endif /* DEBUG */
345 
346  /* restore */
347  pf = pf_old;
348  pIn = pIn_old;
349  sCurrPath = sOldPath;
350  sCurrFile = sOldFile;
351 
352  silent_cerr("Invalid file <" << sfname << "> "
353  "at line " << GetLineData() << std::endl);
354  throw ErrFile(MBDYN_EXCEPT_ARGS);
355  }
356 
358 
359  /* Cambio di directory */
360 #ifdef USE_INCLUDE_PARSER
361  sCurrPath = NULL;
362  sCurrFile = NULL;
363  char* stmp = NULL;
364  SAFESTRDUP(stmp, sfname);
365  char* s = (char*)stmp + strlen(sfname);
366  while (--s >= stmp) {
367  if (s[0] == DIR_SEP) {
368  char c = s[1];
369  s[1] = '\0';
370  if (chdir(stmp)) {
371  silent_cerr("Error in chdir, path="
372  << stmp << std::endl);
374  }
375  char p[PATH_MAX];
376  if (getcwd(p, sizeof(p)) == NULL) {
377  silent_cerr("Error in getcwd()" << std::endl);
378  SAFEDELETEARR(stmp);
380  }
381  SAFESTRDUP(sCurrPath, p);
382  DEBUGCOUT("Current directory is \"" << sCurrPath
383  << "\"" << std::endl);
384 
385  s[1] = c;
386  break;
387  }
388  }
389  s++;
390  SAFESTRDUP(sCurrFile, s);
391  DEBUGCOUT("Opening file <" << sCurrFile << '>' << std::endl);
392 
393  SAFEDELETEARR(stmp);
394 
395  if (sCurrPath == NULL) {
396  char s[PATH_MAX];
397  if (getcwd(s, sizeof(s)) == NULL) {
398  silent_cerr("Error in getcwd()" << std::endl);
400  }
401  SAFESTRDUP(sCurrPath, s);
402  DEBUGCOUT("Current directory is \"" << sCurrPath
403  << "\"" << std::endl);
404  }
405 #endif /* USE_INCLUDE_PARSER */
406 
407  MyInput* pmi = NULL;
408 #ifdef USE_INCLUDE_PARSER
410  MyInput,
411  MyInput(pf_old, pIn_old, sOldPath, sOldFile));
412 #else /* !USE_INCLUDE_PARSER */
413  SAFENEWWITHCONSTRUCTOR(pmi, MyInput, MyInput(pf_old, pIn_old));
414 #endif /* !USE_INCLUDE_PARSER */
415 
416  myinput.push(pmi);
417 
418  /* FIXME: mettere un test se c'e' il punto e virgola? */
420 
421  return true;
422 }
423 
424 void
426 {
427  if (!fCheckStack()) {
429  }
430 }
431 
432 /*
433  * returns a dynamically allocated string with environment variables expanded
434  */
435 static char *
436 expand_environment(const char *in)
437 {
438  char *out = NULL;
439 #define MAXSUBST 10
440  struct {
441  unsigned start;
442  unsigned end;
443  const char *value;
444  unsigned length;
445  } subst[MAXSUBST];
446  unsigned cnt = 0, c;
447 
448  DEBUGCOUT(">> expand_environment: " << in << std::endl);
449 
450  subst[cnt].start = 0;
451  subst[cnt].end = 0;
452  subst[cnt].value = NULL;
453  subst[cnt].length = 0;
454  for (c = 0; in[c]; c++) {
455  if (in[c] == '$') {
456  if (cnt >= MAXSUBST - 2) {
457  silent_cerr("too many substitutions in \""
458  << in << "\"" << std::endl);
459  return NULL;
460  }
461 
462  subst[cnt].end = c;
463  if (in[c + 1] == '$') {
464  c++;
465  subst[cnt].start = c;
466  subst[cnt].value = "";
467  subst[cnt].length = 0;
468  continue;
469  }
470 
471  c++;
472  unsigned namepos = c;
473  if (in[c] == '{') {
474  const char *end = std::strchr(&in[c], '}');
475 
476  if (end == NULL) {
477  silent_cerr("missing trailing \"}\" "
478  "in \"" << in << "\""
479  << std::endl);
480  return NULL;
481  }
482 
483  namepos++;
484  unsigned l = end - &in[namepos];
485  char buf[l + 1];
486  memcpy(buf, &in[namepos], l);
487  buf[l] = '\0';
488  subst[cnt].value = getenv(buf);
489  if (subst[cnt].value == NULL) {
490  silent_cerr("unable to find "
491  "environment "
492  "variable \""
493  << buf << "\""
494  << std::endl);
495  return NULL;
496  }
497 
498  c = end - &in[0] + 1;
499 
500  } else {
501  if (in[c] != '_' && !isalpha(in[c])) {
502  silent_cerr("illegal leading char "
503  "in environment "
504  "variable name in \""
505  << in << "\""
506  << std::endl);
507  return NULL;
508  }
509 
510  for (c++; in[c]; c++) {
511  if (in[c] != '_' && !isalnum(in[c])) {
512  break;
513  }
514  }
515 
516  unsigned l = &in[c] - &in[namepos];
517  char buf[l + 1];
518  memcpy(buf, &in[namepos], l);
519  buf[l] = '\0';
520 
521  subst[cnt].value = getenv(buf);
522  if (subst[cnt].value == NULL) {
523  silent_cerr("unable to find "
524  "environment "
525  "variable \""
526  << buf << "\""
527  << std::endl);
528  return NULL;
529  }
530  }
531 
532  /* can't be NULL */
533  subst[cnt].length = strlen(subst[cnt].value);
534 
535  cnt++;
536  subst[cnt].start = c;
537 
538  /* because it's incremented again by "for" */
539  c--;
540  }
541  }
542  subst[cnt].end = c;
543  subst[cnt].value = NULL;
544  subst[cnt].length = 0;
545 
546  unsigned len = 0;
547  for (c = 0; c < cnt; c++) {
548  len += (subst[c].end - subst[c].start) + subst[c].length;
549  }
550  len += subst[c].end - subst[c].start;
551 
552  SAFENEWARR(out, char, len + 1);
553 
554  unsigned p = 0;
555  for (c = 0; c < cnt; c++) {
556  unsigned l = subst[c].end - subst[c].start;
557  if (l > 0) {
558  memcpy(&out[p], &in[subst[c].start], l);
559  p += l;
560  }
561  if (subst[c].length > 0) {
562  memcpy(&out[p], subst[c].value, subst[c].length);
563  p += subst[c].length;
564  }
565  }
566  unsigned l = subst[c].end - subst[c].start;
567  if (l > 0) {
568  memcpy(&out[p], &in[subst[c].start], l);
569  p += l;
570  }
571  out[p] = '\0';
572 
573  DEBUGCOUT("<< expand_environment: " << out << std::endl);
574 
575  return out;
576 }
577 
578 static char *
579 resolve_filename(const char *filename_in)
580 {
581  char *res = NULL,
582  *filename = NULL;;
583 
584  if (strchr(filename_in, '$')) {
585  filename = expand_environment(filename_in);
586  if (filename == NULL) {
587  goto error_return;
588  }
589  } else {
590  filename = (char *)filename_in;
591  }
592 
593  if (filename[0] == '~') {
594  filename++;
595  if (filename[0] == DIR_SEP) {
596  /* do environment stuff */
597  char *home;
598 
599  home = getenv("HOME");
600  if (home == NULL) {
601  goto error_return;
602  }
603 
604  char *s = NULL;
605  int l, ll;
606 
607  l = strlen(home);
608  ll = l + strlen(filename) + 1;
609  SAFENEWARR(s, char, ll);
610 
611  strncpy(s, home, l);
612  strcpy(s + l, filename);
613 
614  res = s;
615  goto error_return;
616 
617 #if defined(HAVE_PWD_H)
618  } else {
619  const char *p;
620 
621  p = std::strchr(filename, DIR_SEP);
622  if (p == NULL) {
623  goto error_return;
624  }
625 
626  int l = p - filename;
627 
628  char buf[l + 1];
629  memcpy(buf, filename, l);
630  buf[l] = '\0';
631 
632  /* do passwd stuff */
633  struct passwd *pw;
634 
635  pw = getpwnam(buf);
636 
637  if (pw == NULL ) {
638  goto error_return;
639  }
640 
641  l = strlen(pw->pw_dir);
642  int ll = l + strlen(p) + 1;
643  char *s = NULL;
644  SAFENEWARR(s, char, ll);
645  strncpy(s, pw->pw_dir, l);
646  strcpy(s + l, p);
647 
648  res = s;
649  goto error_return;
650 #endif /* HAVE_PWD_H */
651  }
652  }
653 
654 error_return:;
655  if (filename != NULL) {
656  if (res == NULL) {
657  if (filename != filename_in) {
658  res = filename;
659  } else {
660  SAFESTRDUP(res, filename_in);
661  }
662  } else {
663  if (filename != filename_in) {
664  SAFEDELETEARR(filename);
665  }
666  }
667  }
668 
669  return res;
670 }
671 
672 const char*
674 {
675  const char *s = GetStringWithDelims(Del);
676  if (s == 0) {
677  return 0;
678  }
679 
680  const char *stmp = resolve_filename(s);
681  if (stmp == NULL) {
682  return 0;
683 
684  } else {
685  if (strlen(stmp) >= iDefaultBufSize) {
686  SAFEDELETEARR(stmp);
687  return 0;
688  }
689  strcpy(sStringBuf, stmp);
690  SAFEDELETEARR(stmp);
691  }
692 
693  return sStringBuf;
694 }
695 
698 {
699  ErrOut LineData;
700  LineData.sFileName = sCurrFile;
701  LineData.sPathName = (strcmp(sCurrPath, sInitialPath) == 0) ? 0 : sCurrPath;
702  LineData.iLineNumber = GetLineNumber();
703  return LineData;
704 }
705 
706 /* IncludeParser - end */
707 
708 
InputStream * pis
Definition: parsinc.h:123
const char * sFileName
Definition: parser.h:304
IncludeParser(MathParser &MP, InputStream &streamIn, const char *initial_file="initial file")
Definition: parsinc.cc:120
#define PATH_MAX
Definition: parsinc.cc:49
long int flag
Definition: mbdyn.h:43
static char * filename
Definition: ann_sf.c:71
#define MBDYN_EXCEPT_ARGS
Definition: except.h:63
unsigned int iLineNumber
Definition: parser.h:306
bool SetDescData(const std::string &name, DescRead *rf)
Definition: parser.cc:301
static void InitDescData(void)
Definition: parsinc.cc:98
#define MAXSUBST
virtual HighParser::ErrOut GetLineData(void) const
Definition: parser.cc:681
#define SAFEDELETEARR(pnt)
Definition: mynewmem.h:713
virtual const char * GetFileName(enum Delims Del=DEFAULTDELIM)
Definition: parsinc.cc:673
std::ifstream * pf
Definition: parser.h:420
Token CurrToken
Definition: parser.h:435
virtual ~IncludeParser(void)
Definition: parsinc.cc:149
#define DEBUGCERR(msg)
Definition: myassert.h:235
#define NO_OP
Definition: myassert.h:74
virtual void Eof(void)
Definition: parsinc.cc:425
bool Read(HighParser &HP)
Definition: parsinc.cc:59
bool Include_int(void)
Definition: parsinc.cc:281
static char * expand_environment(const char *in)
Definition: parsinc.cc:436
std::stack< MyInput * > myinput
Definition: parsinc.h:143
#define DEBUGCOUT(msg)
Definition: myassert.h:232
virtual const char * GetStringWithDelims(enum Delims Del=DEFAULTDELIM, bool escape=true)
Definition: parser.cc:1228
const char DIR_SEP
Definition: filename.h:88
const unsigned int iDefaultBufSize
Definition: parser.h:133
#define ASSERT(expression)
Definition: colamd.c:977
flag fCheckStack(void)
Definition: parsinc.cc:225
#define SAFENEWWITHCONSTRUCTOR(pnt, item, constructor)
Definition: mynewmem.h:698
static std::stack< cleanup * > c
Definition: cleanup.cc:59
char * sInitialPath
Definition: parsinc.h:145
virtual bool IsArg(void)
Definition: parser.cc:807
InputStream * pIn
Definition: parser.h:419
#define SAFESTRDUP(pnt, src)
Definition: mynewmem.h:707
static char * resolve_filename(const char *filename_in)
Definition: parsinc.cc:579
char * sCurrPath
Definition: parsinc.h:144
#define SAFENEWARR(pnt, item, sz)
Definition: mynewmem.h:701
std::ifstream * pfile
Definition: parsinc.h:122
virtual int GetLineNumber(void) const
Definition: parser.cc:674
char sStringBuf[iDefaultBufSize]
Definition: parser.h:423
static unsigned desc_done
Definition: parsinc.cc:95
static doublereal buf[BUFSIZE]
Definition: discctrl.cc:333
virtual HighParser::ErrOut GetLineData(void) const
Definition: parsinc.cc:697
bool Read(HighParser &HP)
Definition: parsinc.cc:71
virtual void Close(void)
Definition: parsinc.cc:155
char * sCurrFile
Definition: parsinc.h:146
#define SAFEDELETE(pnt)
Definition: mynewmem.h:710
const char * sPathName
Definition: parser.h:305