1 /*
2   MusicXML Library
3   Copyright (C) Grame 2006-2013
4 
5   This Source Code Form is subject to the terms of the Mozilla Public
6   License, v. 2.0. If a copy of the MPL was not distributed with this
7   file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9   Grame Research Laboratory, 11, cours de Verdun Gensoul 69002 Lyon - France
10   research@grame.fr
11 */
12 
13 #ifndef ___utilities___
14 #define ___utilities___
15 
16 #include <string>
17 #include <cassert>
18 
19 #include <iostream>
20 #include <sstream>
21 
22 #include <ctime>
23 
24 #include <set>
25 #include <list>
26 
27 #include <functional>
28 #include <algorithm>
29 
30 #include <string.h>
31 
32 /* JMI
33 #ifdef WIN32
34   // JMI
35 #else
36   #include <iconv.h>
37 #endif
38 */
39 
40 #include "smartpointer.h"
41 #include "basevisitor.h"
42 
43 
44 namespace MusicXML2
45 {
46 
47 //______________________________________________________________________________
48 class EXP timingItem : public smartable
49 {
50   public:
51     enum timingItemKind { kMandatory, kOptional };
52 
53     static SMARTP<timingItem> createTimingItem (
54       std::string    activity,
55       std::string    description,
56       timingItemKind kind,
57       std::clock_t   startClock,
58       std::clock_t   endClock);
59 
60     timingItem (
61       std::string    activity,
62       std::string    description,
63       timingItemKind kind,
64       std::clock_t   startClock,
65       std::clock_t   endClock);
66 
67     std::string           fActivity;
68     std::string           fDescription;
69     timingItemKind        fKind;
70     clock_t               fStartClock;
71     clock_t               fEndClock;
72 };
73 
74 typedef SMARTP<timingItem> S_timingItem;
75 
76 class EXP timing {
77   public:
78        timing ();
79     virtual ~timing ();
80 
81     // global variable for general use
82     static timing gTiming;
83 
84     // add an item
85     void                  appendTimingItem (
86                             std::string    activity,
87                             std::string    description,
88                             timingItem::timingItemKind
89                                            kind,
90                             clock_t        startClock,
91                             clock_t        endClock);
92 
93     // print
94     void                  print (std::ostream& os) const;
95 
96   private:
97 
98     std::list<S_timingItem>
99                           fTimingItemsList;
100 };
101 EXP std::ostream& operator<< (std::ostream& os, const timing& tim);
102 
103 //______________________________________________________________________________
104 class EXP indenter
105 {
106   public:
107 
108     indenter (std::string spacer = "  ");
109     virtual ~indenter ();
110 
111     // get the indent
getIndent()112     int                   getIndent () const
113                               { return fIndent; }
114 
115     // increase the indentation by 1
116     indenter&             operator++ (const int value);
117 
118     // decrease the indentation by 1
119     indenter&             operator-- (const int value);
120 
121     indenter&             increment (int value);
122     indenter&             decrement (int value);
123 
124     // reset the indentation
resetToZero()125     void                  resetToZero ()
126                               { fIndent = 0; }
127 
128     // check indentation value
129     bool                  operator == (const int &value) const
130                               { return fIndent == value; }
131     bool                  operator != (const int &value) const
132                               { return fIndent != value; }
133 
134     // output as much space as specified
135     void                  print (std::ostream& os) const;
136 
137     // get a spacer for adhoc uses, without increasing the indentation
getSpacer()138     std::string           getSpacer () const
139                               { return fSpacer; }
140 
141     // indent a multiline 'R"(...)"' std::string
142     std::string           indentMultiLineString (std::string value);
143 
144     // global variable for general use
145     static indenter       gIndenter;
146 
147   private:
148     int                   fIndent;
149     std::string           fSpacer;
150 };
151 
152 EXP std::ostream& operator<< (std::ostream& os, const indenter& idtr);
153 
154 // useful shortcut macros
155 #define gIndenter indenter::gIndenter
156 #define gTab      indenter::gIndenter.getSpacer ()
157 
158 //______________________________________________________________________________
159 // a stream buffer that prefixes each line
160 // with the current indentation, i.e. spaces
161 
162 /*
163 std::endl declaration:
164 
165   std::endl for ostream
166   ostream& endl (ostream& os);
167 
168   basic template
169   template <class charT, class traits>
170   basic_ostream<charT,traits>& endl (basic_ostream<charT,traits>& os);
171 
172   Insert newline and flush
173   Inserts a new-line character and flushes the stream.
174 
175   Its behavior is equivalent to calling os.put('\n') (or os.put(os.widen('\n')) for character types other than char), and then os.flush().
176 
177 --
178 
179 Reference for this class:
180   https://stackoverflow.com/questions/2212776/overload-handling-of-stdendl
181 */
182 
183 class indentedStreamBuf: public std::stringbuf
184 {
185   private:
186 
187     std::ostream&         fOutputSteam;
188     indenter&             fIndenter;
189 
190   public:
191 
192     // constructor
indentedStreamBuf(std::ostream & outputStream,indenter & idtr)193     indentedStreamBuf (
194       std::ostream& outputStream,
195       indenter&     idtr)
196       : fOutputSteam (outputStream),
197         fIndenter (idtr)
198         {}
199 
200     // indentation
getIndenter()201     indenter&             getIndenter ()
202                               { return fIndenter; }
203 
204     // flush
flush()205     void                  flush ()
206                               { fOutputSteam.flush (); }
207 
208     virtual int           sync ();
209 };
210 
211 //______________________________________________________________________________
212 class EXP indentedOstream: public std::ostream
213 {
214 /*
215 Reference for this class:
216   https://stackoverflow.com/questions/2212776/overload-handling-of-stdendl
217 
218 Usage:
219   indentedOstream myStream (std::cout);
220 
221   myStream <<
222     1 << 2 << 3 << std::endl <<
223     5 << 6 << std::endl <<
224     7 << 8 << std::endl;
225 */
226 
227   private:
228     // indentedOstream just uses an indentedStreamBuf
229     indentedStreamBuf     fIndentedStreamBuf;
230 
231   public:
232 
233     // constructor
indentedOstream(std::ostream & str,indenter & idtr)234     indentedOstream (
235       std::ostream&  str,
236       indenter&      idtr)
237       : std::ostream (&fIndentedStreamBuf),
238         fIndentedStreamBuf (str, idtr)
239         {}
240 
241     // destructor
~indentedOstream()242     virtual ~indentedOstream ()
243         {};
244 
245     // flush
flush()246     void                  flush ()
247                               { fIndentedStreamBuf.flush (); }
248 
249     // indentation
getIndenter()250     indenter&             getIndenter ()
251                               { return fIndentedStreamBuf.getIndenter (); }
252 
incrIdentation()253     void                  incrIdentation ()
254                               { fIndentedStreamBuf.getIndenter ()++; }
255 
decrIdentation()256     void                  decrIdentation ()
257                               { fIndentedStreamBuf.getIndenter ()--; }
258 
259     // global variables for general use
260     static indentedOstream
261                           gOutputIndentedOstream;
262     static indentedOstream
263                           gLogIndentedOstream;
264     static indentedOstream
265                           gNullIndentedOstream;
266 };
267 
268 // useful shortcut macros
269 #define gOutputOstream indentedOstream::gOutputIndentedOstream
270 #define gLogOstream    indentedOstream::gLogIndentedOstream
271 #define gNullOstream   indentedOstream::gNullIndentedOstream
272 
273 //______________________________________________________________________________
274 struct stringQuoteEscaper
275 {
276   /* usage:
277       string dest = "";
278       for_each( source.begin (), source.end (), stringQuoteEscaper (dest));
279   */
280 
281   std::string&            target;
282 
stringQuoteEscaperstringQuoteEscaper283   explicit                stringQuoteEscaper (std::string& t)
284                             : target (t)
285                               {}
286 
operatorstringQuoteEscaper287   void                    operator() (char ch) const
288                               {
289                                  if( ch == '"') {
290                                    // or switch on any character that
291                                    // needs escaping like '\' itself
292                                     target.push_back ('\\');
293                                  }
294                                  target.push_back (ch);
295                               }
296 };
297 
298 //______________________________________________________________________________
299 struct stringSpaceRemover
300 {
301   /* usage:
302       std::string dest = "";
303       for_each (
304         source.begin (),
305         source.end (),
306         stringSpaceRemover (dest));
307   */
308 
309   std::string&            target;
310 
stringSpaceRemoverstringSpaceRemover311   explicit                stringSpaceRemover (std::string& t)
312                             : target (t)
313                               {}
314 
operatorstringSpaceRemover315   void                    operator() (char ch) const
316                               {
317                                 if (ch != ' ') {
318                                   target.push_back (ch);
319                                 }
320                               }
321 };
322 
323 //______________________________________________________________________________
324 struct stringSpaceReplacer
325 {
326   /* usage:
327       std::string dest = "";
328       for_each (
329         source.begin (),
330         source.end (),
331         stringSpaceReplacer (dest, ersatz));
332   */
333 
334   std::string&            target;
335   char                    ersatz;
336 
stringSpaceReplacerstringSpaceReplacer337   explicit                stringSpaceReplacer (std::string& t, char ch)
338                             : target (t), ersatz (ch)
339                               {}
340 
operatorstringSpaceReplacer341   void                    operator() (char ch) const
342                               {
343                                 if (ch == ' ')
344                                   target.push_back (ersatz);
345                                 else
346                                   target.push_back (ch);
347                               }
348 };
349 
350 //______________________________________________________________________________
351 std::string replicateString (
352   std::string str,
353   int    times);
354 
355 //______________________________________________________________________________
356 std::string replaceSubstringInString (
357   std::string str,
358   std::string subString,
359   std::string ersatz);
360 
361 //______________________________________________________________________________
362 std::string int2EnglishWord (int n);
363 
364 //______________________________________________________________________________
365 std::string stringNumbersToEnglishWords (std::string str);
366 
367 //______________________________________________________________________________
368 std::set<int> decipherNaturalNumbersSetSpecification (
369   std::string theSpecification,
370   bool        debugMode = false);
371 
372 //______________________________________________________________________________
373 std::set<std::string> decipherStringsSetSpecification (
374   std::string theSpecification,
375   bool        debugMode = false);
376 
377 //______________________________________________________________________________
378 std::list<int> extractNumbersFromString (
379   std::string theString, // can contain "1, 2, 17"
380   bool        debugMode = false);
381 
382 //______________________________________________________________________________
383 // from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
384 // trim string from start
ltrim(std::string & s)385 inline std::string &ltrim (std::string &s) {
386   std::function <int (int)>
387     checkSpace =
388       [] (int x) { return isspace (x); };
389 
390   s.erase (
391     s.begin (),
392     find_if (
393       s.begin (),
394       s.end (),
395       std::not1 (checkSpace)
396       )
397     );
398 
399   return s;
400 }
401 
402 // trim string from end
rtrim(std::string & s)403 inline std::string &rtrim (std::string &s) {
404   std::function <int (int)>
405     checkSpace =
406       [] (int x) { return isspace (x); };
407 
408   s.erase (
409     find_if (
410       s.rbegin (),
411       s.rend (),
412       std::not1 (checkSpace)
413       ).base(),
414     s.end ()
415     );
416 
417   return s;
418 }
419 
420 // trim string from both ends
trim(std::string & s)421 inline std::string &trim (std::string &s) {
422   return ltrim (rtrim (s));
423 }
424 
425 //______________________________________________________________________________
426 std::pair<std::string, std::string> extractNamesPairFromString (
427   std::string theString, // may contain "P1 = Bassoon"
428   char        separator,
429   bool        debugMode = false);
430 
431 //______________________________________________________________________________
432 std::string doubleQuoteStringIfNonAlpha (
433   std::string theString);
434 
435 std::string quoteStringIfNonAlpha (
436   std::string theString);
437 
438 std::string doubleQuoteString (
439   std::string theString);
440 
441 std::string quoteString (
442   std::string theString);
443 
444 //______________________________________________________________________________
445 std::string booleanAsString (bool value);
446 
447 //______________________________________________________________________________
448 std::string singularOrPlural (
449   int number, std::string singularName, std::string pluralName);
450 
451 std::string singularOrPluralWithoutNumber (
452   int number, std::string singularName, std::string pluralName);
453 
454 //______________________________________________________________________________
455 void oahWarning (std::string warningMessage);
456 
457 void oahError (std::string errorMessage);
458 
459 //______________________________________________________________________________
460 std::string escapeDoubleQuotes (std::string s);
461 
462 //______________________________________________________________________________
463 void convertHTMLEntitiesToPlainCharacters (std::string& s);
464 
465 //______________________________________________________________________________
466 void splitStringIntoChunks (
467   std::string             theString,
468   std::string             theSeparator,
469   std::list<std::string>& chunksList);
470 
471 void splitRegularStringAtEndOfLines (
472   std::string             theString,
473   std::list<std::string>& chunksList);
474 
475 void splitHTMLStringContainingEndOfLines ( // JMI
476   std::string             theString,
477   std::list<std::string>& chunksList);
478 
479 //______________________________________________________________________________
480 std::string baseName (const std::string &filename);
481   // wait until c++17 for a standard library containing basename()...
482 
483 //______________________________________________________________________________
484 std::string makeSingleWordFromString (const std::string& theString);
485 
486 
487 } // namespace MusicXML2
488 
489 
490 #endif
491