NCBI C++ ToolKit
file_contents.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: file_contents.cpp 70023 2015-11-30 14:28:08Z gouriano $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Viatcheslav Gorelenkov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 #include "file_contents.hpp"
32 #include "proj_builder_app.hpp"
33 #include "msvc_prj_defines.hpp"
34 #include "ptb_err_codes.hpp"
35 #include <corelib/ncbistr.hpp>
36 
38 
40 {
41  switch (type) {
42  case eMakeType_Undefined: return "";
43  case eMakeType_Expendable: return "EXPENDABLE";
44  case eMakeType_Potential: return "POTENTIAL";
45  case eMakeType_Excluded: return "EXCLUDED";
46  case eMakeType_ExcludedByReq: return "EXCLUDEDBYREQ";
47  default: return "INCORRECT!";
48  }
49 }
50 
51 //-----------------------------------------------------------------------------
53  : m_Type( eMakeType_Undefined ), m_Parent(NULL), m_Raw(false)
54 {
55 }
56 
57 
59  (const CSimpleMakeFileContents& contents)
60 {
61  SetFrom(contents);
62 }
63 
64 
65 CSimpleMakeFileContents& CSimpleMakeFileContents::operator=
66  (const CSimpleMakeFileContents& contents)
67 {
68  if (this != &contents) {
69  SetFrom(contents);
70  }
71  return *this;
72 }
73 
74 
76  const string& file_path, EMakeFileType type)
77 {
78  LoadFrom(file_path, this);
79  m_Type = type;
80  m_Parent = NULL;
81  m_Raw = false;
82 }
83 
85 {
86  LoadFrom(file_path, this);
88  m_Parent = NULL;
89  m_Raw = true;
90 }
91 
92 
94 {
95 }
96 
97 
99 {
100  m_Contents.clear();
102  m_Filename.erase();
103  m_Parent = NULL;
104  m_Raw = false;
105 }
106 
107 
109 {
110  m_Contents = contents.m_Contents;
111  m_Type = contents.m_Type;
112  m_Filename = contents.m_Filename;
114  m_Parent = contents.m_Parent;
115  m_Raw = contents.m_Raw;
116 }
117 
118 
119 void CSimpleMakeFileContents::LoadFrom(const string& file_path,
121 {
122  if (fc->m_ValueSeparator.empty()) {
123  fc->m_ValueSeparator = LIST_SEPARATOR;
124  }
126  fc->Clear();
127 
128  CNcbiIfstream ifs(file_path.c_str(), IOS_BASE::in | IOS_BASE::binary);
129  if ( !ifs )
130  NCBI_THROW(CProjBulderAppException, eFileOpen, file_path);
131 
132  fc->m_Filename = file_path;
133  parser.StartParse();
134 
135  string strline;
136  while ( NcbiGetlineEOL(ifs, strline) )
137  parser.AcceptLine(strline);
138 
139  parser.EndParse();
140 }
141 
143  const string& value)
144 {
145  SKeyValue kv;
146  kv.m_Key = key;
147  kv.m_Value = value;
148  AddReadyKV(kv);
149 }
150 
152 {
154  if (i != m_Contents.end()) {
155  m_Contents.erase(i);
156  }
157 }
158 
159 bool CSimpleMakeFileContents::HasDefinition( const string& key) const
160 {
161  return m_Contents.find(key) != m_Contents.end();
162 }
163 
165  const string& key, const string& value, bool ifnokey /*=true*/) const
166 {
168  if (k != m_Contents.end()) {
169  return find(k->second.begin(), k->second.end(), value) != k->second.end();
170  }
171  return ifnokey;
172 }
173 
174 bool CSimpleMakeFileContents::GetPathValue(const string& key, string& value) const
175 {
176  if (GetValue(key,value)) {
177  string separator;
178  separator += CDirEntry::GetPathSeparator();
179  NStr::ReplaceInPlace(value,"/",separator);
180  return true;
181  }
182  return false;
183 }
184 
185 bool CSimpleMakeFileContents::GetValue(const string& key, list<string>& value) const
186 {
187  value.clear();
189  if (k == m_Contents.end()) {
190  return false;
191  }
192  value = k->second;
193  return true;
194 }
195 
196 bool CSimpleMakeFileContents::GetValue(const string& key, string& value) const
197 {
198  value.erase();
200  if (k == m_Contents.end()) {
201  return false;
202  }
203  value = " ";
204  const list<string>& lst = k->second;
205  list<string>::const_iterator i = lst.begin();
206  if (i != lst.end() && *i != "#") {
207  value = *i;
208  ++i;
209  }
210  for (; i != lst.end(); ++i) {
211  if (*i == "#") {
212  break;
213  }
214  value += ' ';
215  value += *i;
216  }
217  if (!value.empty() && !m_Raw) {
218  string::size_type start, end, done = 0;
219  while ((start = value.find("$(", done)) != string::npos) {
220  end = value.find(")", start);
221  if (end == string::npos) {
223  "Invalid macro definition: " << value);
224  break;
225  }
226  string raw_macro = value.substr(start,end-start+1);
227  if (CSymResolver::IsDefine(raw_macro)) {
228  string macro = CSymResolver::StripDefine(raw_macro);
229  string definition;
230  GetValue(macro, definition);
231  value = NStr::Replace(value, raw_macro, definition);
232  }
233  }
234 #if 0
237  value = NStr::Replace(value,"-static",kEmptyStr);
238 #endif
239  }
240  return true;
241 }
242 
244  const string& key, list<string>& values, EHowToCollect how) const
245 {
247  if (k != m_Contents.end()) {
248  copy(k->second.begin(), k->second.end(), back_inserter(values));
249  }
250  if (m_Parent) {
251  m_Parent->CollectValues(key,values,eAsIs);
252  }
253  if (values.empty()) {
254  return false;
255  }
256 
257  if (how == eSortUnique) {
258  values.sort();
259  values.unique();
260  }
261  else if (how == eMergePlusMinus) {
262  bool erased = false;
263  do {
264  erased = false;
265  for ( list<string>::iterator i = values.begin(); i != values.end(); ++i) {
266  if (i->at(0) == '-') {
267  list<string>::iterator plus;
268  while ((plus = find( i, values.end(), i->c_str()+1)) != values.end()) {
269  values.erase(plus);
270  }
271  values.erase(i);
272  erased = true;
273  break;
274  }
275  }
276  } while (erased);
277  }
278  else if (how == eFirstNonempty) {
279  while ( !values.empty() && values.front().empty()) {
280  values.pop_front();
281  }
282  }
283  return !values.empty();
284 }
285 
286 void CSimpleMakeFileContents::Save(const string& filename) const
287 {
288  CNcbiOfstream ofs(filename.c_str(), IOS_BASE::out | IOS_BASE::trunc );
289  if (ofs.is_open()) {
290  Dump(ofs);
291  }
292 }
293 
294 void CSimpleMakeFileContents::Dump(CNcbiOstream& ostr, const list<string>* skip /*=0*/) const
295 {
296  size_t len=0;
298  if (skip != 0 && find(skip->begin(), skip->end(), p->first) != skip->end()) {
299  continue;
300  }
301  ostr << p->first << " = ";
302  ITERATE(list<string>, m, p->second) {
303  if (len > 60) {
304  ostr << '\\' << endl << " ";
305  len = 0;
306  }
307  ostr << NStr::Replace(*m,"\\","/") << " ";
308  len += m->size() + 1;
309  }
310  ostr << endl;
311  len=0;
312  }
313 }
314 
315 
317  :m_FileContents(fc)
318 {
319 }
320 
321 
323 {
324  m_Continue = false;
325  m_CurrentKV = SKeyValue();
326 }
327 
328 
329 
330 //------------------------------------------------------------------------------
331 // helpers ---------------------------------------------------------------------
332 
333 static bool s_WillContinue(const string& line)
334 {
335  return NStr::EndsWith(line, "\\");
336 }
337 
338 
339 static void s_StripContinueStr(string* str)
340 {
341  str->erase(str->length() -1, 1); // delete last '\'
342  *str += " ";
343 }
344 
345 
346 static bool s_SplitKV(const string& line, SKeyValue& kv)
347 {
348  if ( !NStr::SplitInTwo(line, "=", kv.m_Key, kv.m_Value) )
349  return false;
350 
351  kv.m_Key = NStr::TruncateSpaces(kv.m_Key); // only for key - preserve sp for vals
352  kv.m_Append = NStr::EndsWith(kv.m_Key, "+");
353  if (kv.m_Append) {
354  kv.m_Append = true;
355  NStr::ReplaceInPlace(kv.m_Key, "+", " ");
356  kv.m_Key = NStr::TruncateSpaces(kv.m_Key); // only for key - preserve sp for vals
357  }
358  if ( s_WillContinue(kv.m_Value) )
360 
361  return true;
362 }
363 
364 
365 static bool s_IsKVString(const string& str)
366 {
367  size_t eq_pos = str.find("=");
368  if (eq_pos == NPOS)
369  return false;
370  string mb_key = str.substr(0, eq_pos - 1);
371  return mb_key.find_first_of("$()") == NPOS;
372 }
373 
374 
375 static bool s_IsCommented(const string& str)
376 {
377  return NStr::StartsWith(str, "#");
378 }
379 
380 
381 
383 {
384  string strline = NStr::TruncateSpaces(line);
385  if ( s_IsCommented(strline) )
386  return;
387 
388  if (m_Continue) {
389  m_Continue = s_WillContinue(strline);
390  if ( strline.empty() || strline.find_first_not_of(' ') == string::npos ) {
391  //fix for ill-formed makefiles:
392  m_FileContents->AddReadyKV(m_CurrentKV);
393  return;
394 #if 0
395 // this is dangerous "fix"
396  } else if ( s_IsKVString(strline) ) {
397  //fix for ill-formed makefiles:
398  m_FileContents->AddReadyKV(m_CurrentKV);
399  m_Continue = false; // guard
400  AcceptLine(strline.c_str());
401 #endif
402  }
403  if (m_Continue)
404  s_StripContinueStr(&strline);
405  m_CurrentKV.m_Value += strline;
406  return;
407 
408  } else {
409  const string include_token("include ");
410  if ( NStr::StartsWith(strline, include_token) ) {
411  string include = NStr::TruncateSpaces(
412  strline.substr(include_token.length()));
413  string root;
414  string srcdir_token("$(srcdir)");
415  if (NStr::StartsWith(include, srcdir_token)) {
416  root = CDirEntry( m_FileContents->GetFileName()).GetDir();
417  } else {
418  srcdir_token = "$(top_srcdir)";
419  if (NStr::StartsWith(include, srcdir_token)) {
420  root = GetApp().GetProjectTreeInfo().m_Root;
421  }
422  else {
423 #if 0
424  srcdir_token = "$(builddir)";
425  if (NStr::StartsWith(include, srcdir_token)) {
426  root = GetApp().GetBuildRoot();
427  if (root.empty()) {
428  root = CDirEntry(GetApp().m_Solution).GetDir();
429  }
430  }
431 #endif
432  }
433  }
434  if (!root.empty()) {
435  include = CDirEntry::NormalizePath(
436  CDirEntry::ConcatPath( root,
437  NStr::Replace(include, srcdir_token, "")));
438  LoadInclude(include);
439  }
440  } else
441  if ( s_IsKVString(strline) ) {
442  m_FileContents->AddReadyKV(m_CurrentKV);
443  m_Continue = s_WillContinue(strline);
444  s_SplitKV(strline, m_CurrentKV);
445  return;
446  }
447  }
448 }
449 
451 {
452  EndParse();
453  CNcbiIfstream ifs(file_path.c_str(), IOS_BASE::in | IOS_BASE::binary);
454  if ( !ifs ) {
455  PTB_WARNING_EX(m_FileContents->GetFileName(),
456  ePTB_FileNotFound, "Include file not found: " << file_path);
457  return;
458  }
459  StartParse();
460  string strline;
461  while ( NcbiGetlineEOL(ifs, strline) ) {
462  AcceptLine(strline);
463  }
464  EndParse();
465  StartParse();
466 }
467 
469 {
470  m_FileContents->AddReadyKV(m_CurrentKV);
471  m_Continue = false;
472  m_CurrentKV = SKeyValue();
473 }
474 
475 
477 {
478  if ( kv.m_Key.empty() )
479  return;
480 
481  if (kv.m_Key == "CHECK_CMD") {
482  m_Contents[kv.m_Key].push_back( kv.m_Value);
483  } else {
484  list<string> values;
485 // if (NStr::EndsWith(kv.m_Key,"LIBS")) {
486  if (NStr::FindCase(kv.m_Key,"LIB") != NPOS ||
487  NStr::FindCase(kv.m_Value," -l") != NPOS ||
488  NStr::FindCase(kv.m_Value,"-rpath") != NPOS ||
489  NStr::FindCase(kv.m_Value,"-framework") != NPOS) {
491  } else {
492  if (m_ValueSeparator.empty()) {
494  }
496  }
497 // change '{' into '(', because I rely on that in many places
498  NON_CONST_ITERATE(list<string>, v, values) {
499  string::size_type start, end;
500  while ((start = v->find("${")) != string::npos) {
501  v->replace(start+1, 1, 1, '(');
502  }
503  while ((end = v->find("}")) != string::npos) {
504  v->replace( end, 1, 1, ')');
505  }
506  }
507  list<string>& dest = m_Contents[kv.m_Key];
508  if (!kv.m_Append) {
509  dest.clear();
510  }
511  string value;
512  size_t start_count=0, end_count=0;
513  ITERATE(list<string>, v, values) {
514  string::size_type start, end;
515  if (!value.empty()) {
516  value += ' ';
517  }
518  value += *v;
519  for (start=0; (start = v->find("$(", start)) != string::npos; ++start)
520  ++start_count;
521  for (end=0; (end = v->find(")", end)) != string::npos; ++end)
522  ++end_count;
523  if (start_count == end_count) {
524 // very primitive GNU make built-in expansion functions
525  if (NStr::StartsWith(value, "$(addsuffix")) {
526  string first, second;
527  string func, arg;
529  NStr::SplitInTwo(first, " ", func, arg);
530  list<string> tmp;
532  ITERATE(list<string>, t, tmp) {
533  dest.push_back(*t+arg);
534  }
535  } else {
536  if (kv.m_Key == "SRC" && CSymResolver::IsDefine(value)) {
538  }
539  dest.push_back(value);
540  }
541  start_count = end_count = 0;
542  value.clear();
543  }
544  }
545  }
546 }
547 
548 
CDirEntry –.
Definition: ncbifile.hpp:262
CProjBulderAppException –.
const SProjectTreeInfo & GetProjectTreeInfo(void)
const string & GetBuildRoot(void) const
CSimpleMakeFileContents –.
static void LoadFrom(const string &file_path, CSimpleMakeFileContents *fc)
void RemoveDefinition(const string &key)
bool HasDefinition(const string &key) const
void Dump(CNcbiOstream &ostr, const list< string > *skip=0) const
Debug dump.
bool GetPathValue(const string &key, string &value) const
void SetFrom(const CSimpleMakeFileContents &contents)
bool CollectValues(const string &key, list< string > &values, EHowToCollect how) const
bool DoesValueContain(const string &key, const string &value, bool ifnokey=true) const
void AddDefinition(const string &key, const string &value)
const CSimpleMakeFileContents * m_Parent
bool GetValue(const string &key, string &value) const
void AddReadyKV(const SKeyValue &kv)
void Save(const string &filename) const
static string StripDefine(const string &define)
Definition: resolver.cpp:75
static bool IsDefine(const string &param)
Definition: resolver.cpp:258
void erase(iterator pos)
Definition: map.hpp:167
const_iterator end() const
Definition: map.hpp:152
void clear()
Definition: map.hpp:169
const_iterator find(const key_type &key) const
Definition: map.hpp:153
The NCBI C++ standard methods for dealing with std::string.
std::ofstream out("events_result.xml")
main entry point for tests
string MakeFileTypeAsString(EMakeFileType type)
static bool s_WillContinue(const string &line)
static bool s_IsKVString(const string &str)
static void s_StripContinueStr(string *str)
static bool s_SplitKV(const string &line, SKeyValue &kv)
static bool s_IsCommented(const string &str)
EMakeFileType
@ eMakeType_Undefined
@ eMakeType_Potential
@ eMakeType_Expendable
@ eMakeType_Excluded
@ eMakeType_ExcludedByReq
#define false
Definition: bool.h:36
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
static int trunc
Definition: array_out.c:8
static int type
Definition: getdata.c:31
static const char * str(char *buf, int n)
Definition: stats.c:84
static char tmp[3200]
Definition: utf8.c:42
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define NULL
Definition: ncbistd.hpp:225
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
static string NormalizePath(const string &path, EFollowLinks follow_links=eIgnoreLinks)
Normalize a path.
Definition: ncbifile.cpp:820
string GetDir(EIfEmptyPath mode=eIfEmptyPath_Current) const
Get the directory component for this directory entry.
Definition: ncbifile.cpp:475
static char GetPathSeparator(void)
Get path separator symbol specific for the current platform.
Definition: ncbifile.cpp:433
static string ConcatPath(const string &first, const string &second)
Concatenate two parts of the path for the current OS.
Definition: ncbifile.cpp:776
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
CNcbiIstream & NcbiGetlineEOL(CNcbiIstream &is, string &str, string::size_type *count=NULL)
Read from "is" to "str" the next line (taking into account platform specifics of End-of-Line)
IO_PREFIX::ofstream CNcbiOfstream
Portable alias for ofstream.
Definition: ncbistre.hpp:500
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
#define kEmptyStr
Definition: ncbistr.hpp:123
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3461
static bool EndsWith(const CTempString str, const CTempString end, ECase use_case=eCase)
Check if a string ends with a specified suffix value.
Definition: ncbistr.hpp:5430
#define NPOS
Definition: ncbistr.hpp:133
static string & Replace(const string &src, const string &search, const string &replace, string &dst, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3314
static SIZE_TYPE FindCase(const CTempString str, const CTempString pattern, SIZE_TYPE start, SIZE_TYPE end, EOccurrence which=eFirst)
Find the pattern in the specified range of a string using a case sensitive search.
Definition: ncbistr.hpp:5490
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5412
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3554
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3405
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3186
@ fSplit_Truncate
Definition: ncbistr.hpp:2501
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2498
int i
int len
#define LIST_SEPARATOR_LIBS
#define LIST_SEPARATOR
Separator for list values in registry.
const struct ncbi::grid::netcache::search::fields::KEY key
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
EIPRangeType t
Definition: ncbi_localip.c:101
T plus(T x_)
std::istream & in(std::istream &in_, double &x_)
void copy(Njn::Matrix< S > *matrix_, const Njn::Matrix< T > &matrix0_)
Definition: njn_matrix.hpp:613
#define fc
CProjBulderApp & GetApp(void)
access to App singleton
@ ePTB_MacroInvalid
@ ePTB_FileNotFound
#define PTB_WARNING_EX(file, err_code, msg)
string FilterDefine(const string &define)
Definition: resolver.cpp:326
void AcceptLine(const string &line)
void LoadInclude(const string &file_path)
Key Value struct.
string m_Key
string m_Value
string m_Root
Root of the project tree.
Definition: proj_utils.hpp:58
Definition: type.c:6
done
Definition: token1.c:1
Modified on Wed May 22 11:36:25 2024 by modify_doxy.py rev. 669887