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  // #include "unistd.h"
14 
15 #include <iostream>
16 #include <sstream>
17 #include <cassert>
18 
19 #include <vector>
20 #include <map>
21 
22 #include <iomanip>      // setw, ...
23 
24 #include "rational.h"
25 #include "utilities.h"
26 
27 using namespace std;
28 
29 namespace MusicXML2
30 {
31 
32 //______________________________________________________________________________
createTimingItem(string activity,string description,timingItemKind kind,clock_t startClock,clock_t endClock)33 S_timingItem timingItem::createTimingItem (
34   string         activity,
35   string         description,
36   timingItemKind kind,
37   clock_t        startClock,
38   clock_t        endClock)
39 {
40   timingItem* o = new timingItem (
41     activity,
42     description,
43     kind,
44     startClock,
45     endClock);
46   assert(o!=0);
47   return o;
48 }
49 
timingItem(string activity,string description,timingItemKind kind,clock_t startClock,clock_t endClock)50 timingItem::timingItem (
51   string         activity,
52   string         description,
53   timingItemKind kind,
54   clock_t        startClock,
55   clock_t        endClock)
56 {
57   fActivity    = activity;
58   fDescription = description;
59   fKind        = kind;
60   fStartClock  = startClock;
61   fEndClock    = endClock;
62 }
63 
timing()64 timing::timing ()
65 {}
66 
~timing()67 timing::~timing ()
68 {}
69 
70 
appendTimingItem(string activity,string description,timingItem::timingItemKind kind,clock_t startClock,clock_t endClock)71 void timing::appendTimingItem (
72   string         activity,
73   string         description,
74   timingItem::timingItemKind
75                  kind,
76   clock_t        startClock,
77   clock_t        endClock)
78 {
79   S_timingItem
80     timingItem =
81       timingItem::createTimingItem (
82         activity,
83         description,
84         kind,
85         startClock,
86         endClock);
87 
88   fTimingItemsList.push_back (timingItem);
89 }
90 
operator <<(ostream & os,const timing & tim)91 ostream& operator<< (ostream& os, const timing& tim) {
92   tim.print(os);
93   return os;
94 }
95 
print(ostream & os) const96 void timing::print (ostream& os) const
97 {
98   const int
99     activityWidth     =  8,
100     descriptionWidth  = 31,
101     kindWidth         =  9,
102     secondsWidth      =  9,
103     secondsPrecision  =  6;
104 
105   clock_t
106     totalClock          = 0.0,
107     totalMandatoryClock = 0.0,
108     totalOptionalClock  = 0.0;
109 
110   os << endl << "Timing information:" << endl << endl <<
111     setw (activityWidth) << "Activity" << "  " <<
112     setw (descriptionWidth) << "Description" << "  " <<
113     setw (kindWidth)     << "Kind" << "  " <<
114     setw (secondsWidth)  << "CPU (sec)" << endl <<
115     setw (activityWidth) << replicateString ("-", activityWidth) << "  " <<
116     setw (descriptionWidth) << replicateString ("-", descriptionWidth) << "  " <<
117     setw (kindWidth) << replicateString ("-", kindWidth) << "  " <<
118     setw (secondsWidth) << replicateString ("-", secondsWidth) << endl << endl;
119 
120   for ( list<S_timingItem>::const_iterator i=fTimingItemsList.begin (); i!=fTimingItemsList.end (); i++) {
121     clock_t timingItemClock = (*i)->fEndClock - (*i)->fStartClock;
122     totalClock += timingItemClock;
123 
124     os << left <<
125       setw (activityWidth) << (*i)->fActivity << "  " <<
126       setw (descriptionWidth) << (*i)->fDescription << "  ";
127 
128     switch ((*i)->fKind) {
129       case timingItem::kMandatory:
130         totalMandatoryClock += timingItemClock;
131         os << setw (kindWidth) << "mandatory";
132         break;
133       case timingItem::kOptional:
134         totalOptionalClock += timingItemClock;
135         os << setw (kindWidth) << "optional";
136         break;
137     } // switch
138 
139     os << "  " <<
140       setw (secondsWidth) << setprecision(secondsPrecision) <<
141     left << float(timingItemClock) / CLOCKS_PER_SEC << endl;
142   } // for
143 
144   const int
145     totalClockWidth          =  7,
146     totalMandatoryClockWidth =  9,
147     totalOptionalClockWidth  = 10,
148     totalsPrecision          =  6;
149 
150   os << left <<
151     endl <<
152     setw (totalClockWidth)            << "Total" <<
153     "    " <<
154     setw (totalMandatoryClockWidth)   << "Mandatory" <<
155     "  " <<
156     setw (totalOptionalClockWidth)    << "Optional" <<
157     endl <<
158 
159     setw (totalClockWidth) <<
160     replicateString ("-", totalClockWidth) <<
161     "    " <<
162     setw (totalMandatoryClockWidth) <<
163     replicateString ("-", totalMandatoryClockWidth) <<
164     "  " <<
165     setw (secondsWidth) <<
166     replicateString ("-", secondsWidth) <<
167     setprecision(totalsPrecision) <<
168     endl <<
169 
170     setw (totalClockWidth) <<
171     float(totalClock) / CLOCKS_PER_SEC <<
172     "    " <<
173     setw (totalMandatoryClockWidth) <<
174     float(totalMandatoryClock) / CLOCKS_PER_SEC <<
175     "  " <<
176     setw (totalOptionalClockWidth) <<
177     float(totalOptionalClock) / CLOCKS_PER_SEC <<
178     endl <<
179     endl;
180 }
181 
182 timing timing::gTiming;
183 
184 //______________________________________________________________________________
185 //#define DEBUG_INDENTER
186 
187 indenter indenter::gIndenter;
188 
indenter(string spacer)189 indenter::indenter (string spacer)
190 {
191   fIndent = 0;
192   fSpacer = spacer;
193 }
194 
~indenter()195 indenter::~indenter ()
196 {}
197 
operator ++(const int value)198 indenter& indenter::operator++ (const int value)
199 {
200   fIndent++;
201 
202 #ifdef DEBUG_INDENTER
203   gLogOstream <<
204     "% INDENTER: " << fIndent <<
205     endl;
206 #endif
207 
208   return *this;
209 }
210 
operator --(const int value)211 indenter& indenter::operator-- (const int value)
212 {
213   fIndent--;
214 
215   if (fIndent < 0) {
216     gLogOstream <<
217       endl <<
218       "% ### Indentation has become negative: " <<  fIndent <<
219       endl << endl;
220 
221 #ifdef DEBUG_INDENTER
222     assert(false);
223 #endif
224   }
225 
226 #ifdef DEBUG_INDENTER
227   else {
228     gLogOstream <<
229       "% INDENTER: " << fIndent <<
230       endl;
231   }
232 #endif
233 
234   return *this;
235 }
236 
increment(int value)237 indenter& indenter::increment (int value)
238 {
239   fIndent += value;
240 
241   if (fIndent < 0) {
242     gLogOstream <<
243       endl <<
244       "% ### Indentation has become negative: " <<  fIndent <<
245       endl << endl;
246 
247 #ifdef DEBUG_INDENTER
248     assert(false);
249 #endif
250   }
251 
252 #ifdef DEBUG_INDENTER
253   else {
254     gLogOstream <<
255       "% INDENTER: " << fIndent <<
256       endl;
257   }
258 #endif
259 
260   return *this;
261 }
262 
decrement(int value)263 indenter& indenter::decrement (int value)
264 {
265   fIndent -= value;
266 
267   if (fIndent < 0) {
268     gLogOstream <<
269       endl <<
270       "% ### Indentation has become negative: " <<  fIndent <<
271       endl << endl;
272 
273 #ifdef DEBUG_INDENTER
274     assert(false);
275 #endif
276   }
277 
278 #ifdef DEBUG_INDENTER
279   else {
280     gLogOstream <<
281       "% INDENTER: " << fIndent <<
282       endl;
283   }
284 #endif
285 
286   return *this;
287 }
288 
indentMultiLineString(string value)289 string indenter::indentMultiLineString (string value)
290 {
291   stringstream  s;
292 
293   // add indentation ahead of all lines inside 'value'
294   istringstream inputStream (value);
295   string        line;
296 
297   while (getline (inputStream, line)) {
298     s << line;
299 
300     if (inputStream.eof()) break;
301 
302     s << endl;
303     this->print (s);
304   } // while
305 
306   return s.str ();
307 }
308 
operator <<(ostream & os,const indenter & idtr)309 ostream& operator<< (ostream& os, const indenter& idtr) {
310   idtr.print(os);
311   return os;
312 }
313 
print(ostream & os) const314 void indenter::print (ostream& os) const
315 {
316   int i = fIndent;
317 
318   while (i-- > 0) os << fSpacer;
319 }
320 
321 //______________________________________________________________________________
sync()322 int indentedStreamBuf::sync ()
323 {
324   // When we sync the stream with fOutputSteam:
325   // 1) output the indentation then the buffer
326   // 2) reset the buffer
327   // 3) flush the actual output stream we are using.
328 
329   std::size_t strSize = str ().size ();
330 
331   // fetch the last non-space character in the buffer
332   // caution: the '\n' is present as the last character!
333   std::size_t found = str ().find_last_not_of(' ', strSize - 2);
334 
335   // this can be uncommented to see low level informations
336   // fOutputSteam << "% strSize: " << strSize << ", found: " << found << '\n';
337 
338   // output the indenter
339   fOutputSteam << fIndenter;
340 
341   // output the buffer
342   if (found == strSize - 3) {
343     // don't output the trailing spaces, but output the end of line
344     fOutputSteam << str ().substr (0, found + 1) << '\n';
345   }
346   else {
347     // output the whole buffer
348     fOutputSteam << str ();
349   }
350 
351   // reset the buffer
352   str ("");
353 
354   // flush the output stream
355   fOutputSteam.flush ();
356 
357   return 0;
358 }
359 
360 //______________________________________________________________________________
361 indentedOstream indentedOstream::gOutputIndentedOstream (
362   cout, indenter::gIndenter);
363 
364 indentedOstream indentedOstream::gLogIndentedOstream (
365   cerr, indenter::gIndenter);
366 
367 // code taken from:
368 // http://comp.lang.cpp.moderated.narkive.com/fylLGJgp/redirect-output-to-dev-null
369 template<typename Ch, typename Traits = std::char_traits<Ch> >
370 struct basic_nullbuf : std::basic_streambuf<Ch, Traits>
371 {
372   typedef std::basic_streambuf<Ch, Traits> base_type;
373   typedef typename base_type::int_type int_type;
374   typedef typename base_type::traits_type traits_type;
375 
overflowMusicXML2::basic_nullbuf376   virtual int_type overflow (int_type c) {
377     return traits_type::not_eof (c);
378   }
379 };
380 
381 // convenient typedefs
382 typedef basic_nullbuf <char>    nullbuf;
383 //typedef basic_nullbuf <wchar_t> wnullbuf;
384 
385 // buffers and streams
386 nullbuf cnull_obj;
387 //wnullbuf wcnull_obj;
388 
389 std::ostream cnull  (& cnull_obj);
390 //std::wostream wcnull (& wcnull_obj);
391 
392 indentedOstream indentedOstream::gNullIndentedOstream (
393   cnull, indenter::gIndenter);
394 
395 //______________________________________________________________________________
replicateString(string str,int times)396 string replicateString (
397   string str,
398   int    times)
399 {
400   string result;
401 
402   for (int i = 0; i < times; i++)
403     result += str;
404 
405   return result;
406 }
407 
408 //______________________________________________________________________________
replaceSubstringInString(std::string str,std::string subString,std::string ersatz)409 string replaceSubstringInString (
410   std::string str,
411   std::string subString,
412   std::string ersatz)
413 {
414   string result = str;
415 
416   size_t found = result.find (subString);
417 
418   if (found != string::npos) {
419     result.replace (found, subString.size (), ersatz);
420   }
421 
422   return result;
423 }
424 
425 //______________________________________________________________________________
int2EnglishWord(int n)426 string int2EnglishWord (int n)
427 {
428   stringstream s;
429 
430   if (n < 0) {
431     s << "Minus_";
432     n = -n;
433 
434 //    assert(false); // JMI
435   }
436 
437   if     (n >= 1000) {
438     int nDiv1000    = n / 1000;
439     int nModulo1000 = n % 1000;
440 
441     return
442       int2EnglishWord (nDiv1000) +
443       "Thousand" +
444       int2EnglishWord (nModulo1000);
445   }
446 
447   else if (n >= 100) {
448   //return "LargerThanNinetyNine";
449     int nDiv100    = n / 100;
450     int nModulo100 = n % 100;
451 
452     return
453       int2EnglishWord (nDiv100) +
454       "HundredAnd" +
455       int2EnglishWord (nModulo100);
456   }
457 
458   else {
459     switch (n) {
460       case 0:
461         s << "Zero";
462         break;
463       case 1:
464         s << "One";
465         break;
466       case 2:
467         s << "Two";
468         break;
469       case 3:
470         s << "Three";
471         break;
472       case 4:
473         s << "Four";
474         break;
475       case 5:
476         s << "Five";
477         break;
478       case 6:
479         s << "Six";
480         break;
481       case 7:
482         s << "Seven";
483         break;
484       case 8:
485         s << "Eight";
486         break;
487       case 9:
488         s << "Nine";
489         break;
490      case 10:
491         s << "Ten";
492         break;
493       case 11:
494         s << "Eleven";
495         break;
496       case 12:
497         s << "Twelve";
498         break;
499       case 13:
500         s << "Thirteen";
501         break;
502       case 14:
503         s << "Fourteen";
504         break;
505       case 15:
506         s << "Fifteen";
507         break;
508       case 16:
509         s << "Sixteen";
510         break;
511       case 17:
512         s << "Seventeen";
513         break;
514       case 18:
515         s << "Eighteen";
516         break;
517       case 19:
518         s << "Nineteen";
519         break;
520 
521       default: {
522         // n >= 20
523         int nDiv10    = n / 10;
524         int nModulo10 = n % 10;
525 
526         switch (nDiv10) {
527           case 2:
528             s << "Twenty";
529             break;
530           case 3:
531             s << "Thirty";
532             break;
533           case 4:
534             s << "Fourty";
535             break;
536           case 5:
537             s << "Fifty";
538             break;
539           case 6:
540             s << "Sixty";
541             break;
542           case 7:
543             s << "Seventy";
544             break;
545           case 8:
546             s << "Eighty";
547             break;
548           case 9:
549             s << "Ninety";
550             break;
551         } // switch
552         s << int2EnglishWord (nModulo10);
553       } // default
554     } // switch
555   }
556 
557   return s.str ();
558 }
559 
560 //______________________________________________________________________________
stringNumbersToEnglishWords(string str)561 string stringNumbersToEnglishWords (string str)
562 {
563   if (! str.size ()) {
564     return "NONE";
565   }
566 
567   enum workState {
568     kInitialState, kWorkingOnDigits, kWorkingOnNonDigits };
569 
570   vector<string> chunks;
571   vector<int>    states;
572 
573   workState state = kInitialState;
574 
575   string::const_iterator
576     iBegin = str.begin (),
577     iEnd   = str.end (),
578     i      = iBegin;
579 
580   for ( ; ; ) {
581     char ch = (*i);
582 
583     if( isdigit(ch)) {
584       // digit
585       if (state != kWorkingOnDigits) {
586         // create a new chunck for digits
587         chunks.push_back ("");
588         states.push_back (kWorkingOnDigits);
589         state = kWorkingOnDigits;
590       }
591       chunks.back().push_back(ch);
592     }
593     else {
594       // non digit
595       if (state != kWorkingOnNonDigits) {
596         // create a new chunck for non digits
597         chunks.push_back ("");
598         states.push_back (kWorkingOnNonDigits);
599         state = kWorkingOnNonDigits;
600       }
601       chunks.back().push_back(ch);
602     }
603     if (++i == iEnd) break;
604   } // for
605 
606   string result = "";
607 
608   for (unsigned int i = 0; i < chunks.size (); i++) {
609     if (states[i] == kWorkingOnDigits) {
610       int integerValue;
611 
612       istringstream inputStream (chunks[i]);
613 
614       inputStream >> integerValue;
615 
616       result += int2EnglishWord (integerValue);
617     }
618     else {
619       result += chunks[i];
620     }
621   } // for
622 
623   return result;
624 };
625 
626 //______________________________________________________________________________
consumeDecimalNumber(string::const_iterator theStringIterator,string::const_iterator & remainingStringIterator,bool debugMode)627 int consumeDecimalNumber (
628   string::const_iterator  theStringIterator,
629   string::const_iterator& remainingStringIterator,
630   bool                    debugMode)
631 {
632   string::const_iterator cursor = theStringIterator;
633   int    result = 0;
634 
635   if (! isdigit (*cursor)) {
636     gLogOstream <<
637       "consumeDecimalNumber (" << *cursor <<
638       "), " << *cursor << " is no decimal digit!" <<
639       endl;
640     }
641 
642   while (isdigit (*cursor)) {
643     if (debugMode) {
644       gLogOstream <<
645         "--> consumeDecimalNumber: cursor = |" <<
646         *cursor <<
647         "|" <<
648         endl;
649     }
650 
651     result = result*10 + (*cursor-'0');
652 
653     cursor++;
654   } // while
655 
656   remainingStringIterator = cursor;
657 
658   if (debugMode) {
659     gLogOstream <<
660       "--> consumeDecimalNumber: result = " << result <<
661       ", *remainingStringIterator = |" << *remainingStringIterator <<
662       "|" <<
663       endl;
664   }
665 
666   return result;
667 }
668 
669 //______________________________________________________________________________
decipherNaturalNumbersSetSpecification(string theString,bool debugMode)670 set<int> decipherNaturalNumbersSetSpecification (
671   string theString,
672   bool   debugMode)
673 {
674   // A naturalNumbersSetSpecification sample is: "7,15-19,^16-17"
675 
676   set<int> result;
677 
678   if (debugMode) {
679     gLogOstream <<
680       "--> decipherNaturalNumbersSetSpecification, theString = |" << theString <<
681       "|" <<
682       endl;
683   }
684 
685   if (theString.size ()) {
686     string::const_iterator
687       cursor = theString.begin ();
688 
689     while (1) {
690       if (debugMode) {
691         gLogOstream <<
692           "--> decipherNaturalNumbersSetSpecification: cursor = |" <<
693           *cursor << "|" <<
694           endl;
695       }
696 
697       int negated = 0;
698 
699       if (*cursor == '^') {
700         cursor++;
701         negated = 1;
702       }
703 
704       int
705         intervalStartNumber =
706           consumeDecimalNumber (cursor, cursor, debugMode),
707         intervalEndNumber;
708 
709       if (*cursor == '-') {
710         cursor++;
711 
712         if (debugMode) {
713           gLogOstream <<
714             "--> decipherNaturalNumbersSetSpecification after '-' : cursor = |" <<
715             *cursor <<
716             "|" <<
717             endl <<
718             endl;
719         }
720 
721         intervalEndNumber =
722           consumeDecimalNumber (cursor, cursor, debugMode);
723       }
724 
725       else {
726         intervalEndNumber = intervalStartNumber;
727       }
728 
729       if (debugMode) {
730         gLogOstream <<
731           "--> decipherNaturalNumbersSetSpecification" <<
732           ", intervalStartNumber = " << intervalStartNumber <<
733           ", intervalEndNumber = " << intervalEndNumber <<
734           ": *cursor = |" << *cursor << "|" <<
735           endl;
736       }
737 
738       for (int i = intervalStartNumber; i <= intervalEndNumber; i ++) {
739         if (negated) {
740           result.erase (i);
741         }
742         else {
743           result.insert (i);
744         }
745       } // for
746 
747       if (*cursor != ',') {
748         if (debugMode) {
749           gLogOstream <<
750             "--> decipherNaturalNumbersSetSpecification, after non ',' : cursor = |" <<
751             *cursor <<
752             "|" <<
753             endl <<
754             endl;
755         }
756         break;
757       }
758 
759       cursor++;
760 
761       if (debugMode) {
762         gLogOstream <<
763           "--> decipherNaturalNumbersSetSpecification after ',' : cursor = |" <<
764           *cursor <<
765           "|"
766           << endl <<
767           endl;
768       }
769     } // while
770 
771     if (* cursor != '\0') {
772       gLogOstream <<
773         "--> Extraneous characters |" << *cursor <<
774         "| in numbers spec" <<
775         endl << endl;
776     }
777   }
778 
779   return result;
780 }
781 
782 //______________________________________________________________________________
consumeString(string::const_iterator theStringIterator,string::const_iterator & remainingStringIterator,bool debugMode)783 string consumeString (
784   string::const_iterator  theStringIterator,
785   string::const_iterator& remainingStringIterator,
786   bool                    debugMode)
787 {
788   string result;
789 
790 /* JMI
791   string::const_iterator cursor = theStringIterator;
792 
793   while ((*cursor) != ',') {
794     if (debugMode) {
795       gLogOstream <<
796         "--> consumeString: cursor = |" <<
797         *cursor <<
798         "|" <<
799         endl;
800     }
801 
802     result += (*cursor);
803 
804     if (++cursor == theString.end ()) break;
805   } // while
806 
807   remainingStringIterator = cursor;
808 
809   if (debugMode) {
810     gLogOstream <<
811       "--> consumeString: result = " << result <<
812       ", *remainingStringIterator = |" << *remainingStringIterator <<
813       "|" <<
814       endl;
815   }
816 */
817 
818   return result;
819 }
820 
821 //______________________________________________________________________________
decipherStringsSetSpecification(string theString,bool debugMode)822 std::set<string> decipherStringsSetSpecification (
823   string theString,
824   bool   debugMode)
825 {
826   // A integersSetSpecification sample is: "FOO,159,haLLo"
827 
828   set<string> result;
829 
830 /* JMI
831   if (debugMode) {
832     gLogOstream <<
833       "--> decipherStringsSetSpecification, theString = |" << theString <<
834       "|" <<
835       endl;
836   }
837 
838   string::const_iterator
839     cursor = theString.begin ();
840 
841   while (1) {
842     if (debugMode) {
843       gLogOstream <<
844         "--> decipherStringsSetSpecification: cursor = |" <<
845         *cursor << "|" <<
846         endl;
847     }
848 
849     string
850       currentString =
851         consumeString (cursor, theString.end (), debugMode);
852 
853     if (debugMode) {
854       gLogOstream <<
855         "--> decipherStringsSetSpecification" <<
856         ", currentString = " << currentString <<
857         ": *cursor = |" << *cursor << "|" <<
858         endl;
859     }
860 
861     result.insert (currentString);
862 
863     if (*cursor != ',') {
864       if (debugMode) {
865         gLogOstream <<
866           "--> decipherStringsSetSpecification, after non ',' : cursor = |" <<
867           *cursor <<
868           "|" <<
869           endl <<
870           endl;
871       }
872       break;
873     }
874 
875     if (++cursor == theString.end ()) break;
876 
877     if (debugMode) {
878       gLogOstream <<
879         "--> decipherStringsSetSpecification after ',' : cursor = |" <<
880         *cursor <<
881         "|"
882         << endl <<
883         endl;
884     }
885   } // while
886 
887   if (* cursor != '\0') {
888     gLogOstream <<
889       "--> Extraneous characters |" << *cursor <<
890       "| in numbers spec" <<
891       endl << endl;
892   }
893   */
894 
895   return result;
896 }
897 
898 //______________________________________________________________________________
extractNumbersFromString(string theString,bool debugMode)899 list<int> extractNumbersFromString (
900   string theString, // can contain "1, 2, 17"
901   bool   debugMode)
902 {
903   list<int> foundNumbers;
904 
905   if (debugMode) {
906     gLogOstream <<
907       "--> extractNumbersFromString, theString = |" << theString <<
908       "|" <<
909       endl;
910   }
911 
912   if (theString.size ()) {
913     string::const_iterator
914       cursor = theString.begin ();
915 
916     while (1) {
917       if (cursor == theString.end ())
918         break;
919 
920       if (debugMode) {
921         gLogOstream <<
922           "--> extractNumbersFromString: cursor = |" <<
923           *cursor << "|" <<
924           endl;
925       }
926 
927       if (isdigit (*cursor)) {
928         // consume a decimal number
929         int n = 0;
930         while (isdigit (*cursor)) {
931           n = n * 10 + (*cursor - '0');
932           cursor++;
933         } // while
934 
935         // append the number to the list
936         foundNumbers.push_back (n);
937       }
938       else {
939         cursor++;
940       }
941     } // while
942   }
943 
944   return foundNumbers;
945 }
946 
947 
948 //______________________________________________________________________________
extractNamesPairFromString(string theString,char separator,bool debugMode)949 pair<string, string> extractNamesPairFromString (
950   string theString, // can contain "P1 = Bassoon"
951   char        separator,
952   bool        debugMode)
953 {
954   string name1;
955   string name2;
956 
957   if (debugMode) {
958     gLogOstream <<
959       "--> extractNamesPairFromString, theString = |" << theString <<
960       "|" <<
961       endl;
962   }
963 
964   if (theString.size ()) {
965     string::const_iterator
966       cursor = theString.begin ();
967 
968     // fetch name1
969     while (1) {
970       if (cursor == theString.end ())
971         break;
972 
973       if (debugMode) {
974         gLogOstream <<
975           "--> extractNamesPairFromString: cursor = |" <<
976           *cursor << "|" <<
977           endl;
978       }
979 
980       if ((*cursor) == separator) {
981         // found the separator
982         break;
983       }
984 
985       // append the character to name1
986       name1 += *cursor;
987       cursor++;
988     } // while
989 
990     name1 = trim (name1);
991     if (! name1.size ()) {
992       // found an empty name1
993       gLogOstream <<
994         "### ERROR: the first name before the " << separator <<
995         " separator is empty in '" << theString << "'" <<
996         endl;
997     }
998 
999     if (cursor == theString.end ())
1000       gLogOstream <<
1001         "### ERROR: the " << separator <<
1002         " separator is missing in string '" <<
1003         theString << "'" <<
1004         endl;
1005     else
1006       // overtake the separator
1007       cursor++;
1008 
1009     // fetch name2
1010     while (1) {
1011       if (cursor == theString.end ())
1012         break;
1013 
1014       if (debugMode) {
1015         gLogOstream <<
1016           "--> extractNamesPairFromString: cursor = |" <<
1017           *cursor << "|" <<
1018           endl;
1019       }
1020 
1021       if ((*cursor) == '=') {
1022         // found the separator
1023         gLogOstream <<
1024           "### ERROR: the " << separator <<
1025           " separator occurs more than once in string '" <<
1026           theString << "'" <<
1027           endl;
1028         break;
1029       }
1030 
1031       // append the character to name2
1032       name2 += *cursor;
1033       cursor++;
1034     } // while
1035 
1036     name2 = trim (name2);
1037     if (! name2.size ()) {
1038       // found an empty name2
1039       gLogOstream <<
1040         "### ERROR: the second name after the " << separator <<
1041         " separator is empty in '" << theString << "'" <<
1042         endl;
1043     }
1044   }
1045 
1046   return make_pair (name1, name2);
1047 }
1048 
1049 //______________________________________________________________________________
doubleQuoteStringIfNonAlpha(string theString)1050 string doubleQuoteStringIfNonAlpha (
1051   string theString)
1052 {
1053   string result;
1054 
1055   bool   stringShouldBeDoubleQuoted = false;
1056 
1057   if (theString.size ()) {
1058     for (
1059       string::const_iterator i = theString.begin ();
1060       i != theString.end ();
1061       i++
1062     ) {
1063 
1064       if (
1065         ((*i) >= 'a' && (*i) <= 'z')
1066           ||
1067         ((*i) >= 'A' && (*i) <= 'Z')) {
1068         // (*i) is a letter
1069         result += (*i);
1070       }
1071 
1072       else {
1073         // (*i) is not a letter
1074         if ((*i) == ' ')
1075           result += ' '; // TEMP JMI
1076         else
1077           result += (*i);
1078 
1079         stringShouldBeDoubleQuoted = true;
1080       }
1081     } // for
1082   }
1083 
1084   if (stringShouldBeDoubleQuoted) {
1085     return "\"" + result + "\"";
1086   }
1087   else {
1088     return result;
1089   }
1090 }
1091 
1092 //______________________________________________________________________________
quoteStringIfNonAlpha(string theString)1093 string quoteStringIfNonAlpha (
1094   string theString)
1095 {
1096   string result;
1097 
1098   bool   stringShouldBeQuoted = false;
1099 
1100   if (theString.size ()) {
1101     for (
1102       string::const_iterator i = theString.begin ();
1103       i != theString.end ();
1104       i++
1105     ) {
1106 
1107       if (
1108         ((*i) >= 'a' && (*i) <= 'z')
1109           ||
1110         ((*i) >= 'A' && (*i) <= 'Z')) {
1111         // (*i) is a letter
1112         result += (*i);
1113       }
1114 
1115       else {
1116         // (*i) is not a letter
1117         if ((*i) == ' ')
1118           result += ' '; // TEMP JMI
1119         else
1120           result += (*i);
1121 
1122         stringShouldBeQuoted = true;
1123       }
1124     } // for
1125   }
1126 
1127   if (stringShouldBeQuoted) {
1128     return "'" + result + "'";
1129   }
1130   else {
1131     return result;
1132   }
1133 }
1134 
1135 //______________________________________________________________________________
doubleQuoteString(string theString)1136 string doubleQuoteString (
1137   string theString)
1138 {
1139   string result;
1140 
1141   if (theString.size ()) {
1142     for (
1143       string::const_iterator i = theString.begin ();
1144       i != theString.end ();
1145       i++
1146     ) {
1147 
1148       if (
1149         ((*i) >= 'a' && (*i) <= 'z')
1150           ||
1151         ((*i) >= 'A' && (*i) <= 'Z')) {
1152         // (*i) is a letter
1153         result += (*i);
1154       }
1155 
1156       else {
1157         // (*i) is not a letter
1158         if ((*i) == ' ') {
1159           result += ' '; // TEMP JMI
1160         }
1161         else if ((*i) == '"') {
1162           result += "\\\"";
1163         }
1164         else {
1165           result += (*i);
1166         }
1167       }
1168     } // for
1169   }
1170 
1171   return "\"" + result + "\"";
1172 }
1173 
1174 //______________________________________________________________________________
quoteString(string theString)1175 string quoteString (
1176   string theString)
1177 {
1178   string result;
1179 
1180   if (theString.size ()) {
1181     for (
1182       string::const_iterator i = theString.begin ();
1183       i != theString.end ();
1184       i++
1185     ) {
1186 
1187       if (
1188         ((*i) >= 'a' && (*i) <= 'z')
1189           ||
1190         ((*i) >= 'A' && (*i) <= 'Z')) {
1191         // (*i) is a letter
1192         result += (*i);
1193       }
1194 
1195       else {
1196         // (*i) is not a letter
1197         if ((*i) == ' ') {
1198           result += ' '; // TEMP JMI
1199         }
1200         else if ((*i) == '\'') {
1201           result += "\\\'";
1202         }
1203         else {
1204           result += (*i);
1205         }
1206       }
1207     } // for
1208   }
1209 
1210   return "'" + result + "'";
1211 }
1212 
1213 //______________________________________________________________________________
booleanAsString(bool value)1214 string booleanAsString (bool value)
1215 {
1216   return
1217     string (
1218       value
1219         ? "true"
1220         : "false");
1221 }
1222 
1223 //______________________________________________________________________________
singularOrPlural(int number,string singularName,string pluralName)1224 string singularOrPlural (
1225   int number, string singularName, string pluralName)
1226 {
1227   stringstream s;
1228 
1229   s <<
1230     number << ' ';
1231 
1232   if (number <= 1) {
1233     s <<
1234       singularName;
1235   }
1236   else {
1237     s <<
1238       pluralName;
1239   }
1240 
1241   return s.str ();
1242 }
1243 
singularOrPluralWithoutNumber(int number,string singularName,string pluralName)1244 string singularOrPluralWithoutNumber (
1245   int number, string singularName, string pluralName)
1246 {
1247   stringstream s;
1248 
1249   if (number <= 1) {
1250     s <<
1251       singularName;
1252   }
1253   else {
1254     s <<
1255       pluralName;
1256   }
1257 
1258   return s.str ();
1259 }
1260 
1261 //______________________________________________________________________________
oahWarning(string warningMessage)1262 void oahWarning (string warningMessage)
1263 {
1264   gLogOstream <<
1265     "*** WARNING in the options and help: " <<
1266     warningMessage <<
1267     endl;
1268 }
1269 
oahError(string errorMessage)1270 void oahError (string errorMessage)
1271 {
1272   gLogOstream <<
1273     "### ERROR in the options and help: " <<
1274     errorMessage <<
1275     endl;
1276 
1277   exit (33);
1278 }
1279 
1280 //______________________________________________________________________________
escapeDoubleQuotes(string s)1281 string escapeDoubleQuotes (string s)
1282 {
1283   string result;
1284 
1285   for_each (
1286     s.begin (),
1287     s.end (),
1288     stringQuoteEscaper (result));
1289 
1290   // replace occurrences of '\\"' by '\"',
1291   // in case there were already double quotes in string
1292   string
1293     lookedFor = "\\\\\"",
1294     ersatz    = "\\\"";
1295 
1296   for ( ; ; ) {
1297     size_t found = result.find (lookedFor);
1298 
1299     if (found == string::npos)
1300       break;
1301 
1302     result.replace (found, lookedFor.size (), ersatz);
1303   } // for
1304 
1305   return result;
1306 }
1307 
1308 //______________________________________________________________________________
convertHTMLEntitiesToPlainCharacters(string & s)1309 void convertHTMLEntitiesToPlainCharacters (string& s)
1310 {
1311   map<string, string> conversionMap;
1312 
1313   conversionMap ["&"] = "&amp;";
1314   conversionMap ["\""] = "&quot;";
1315   conversionMap ["'"] = "&apos;";
1316   conversionMap ["<"] = "&lt;";
1317   conversionMap [">"] = "&gt;";
1318 
1319   map<string, string>::const_iterator i;
1320 
1321   for (i = conversionMap.begin (); i != conversionMap.end (); ++i) {
1322     string
1323       lookedFor = i->second,
1324       ersatz    = i->first;
1325 
1326     // replace all occurrences of lookedFor by ersatz
1327     for ( ; ; ) {
1328       size_t found = s.find (lookedFor);
1329 
1330       if (found == string::npos)
1331         break;
1332 
1333       s.replace (found, lookedFor.size (), ersatz);
1334     } // for
1335 
1336   } // for
1337 }
1338 
1339 //______________________________________________________________________________
splitStringIntoChunks(std::string theString,std::string theSeparator,std::list<std::string> & chunksList)1340 void splitStringIntoChunks (
1341   std::string             theString,
1342   std::string             theSeparator,
1343   std::list<std::string>& chunksList)
1344 {
1345   //#define DEBUG_SPLITTING
1346 
1347 #ifdef DEBUG_SPLITTING
1348   gLogOstream <<
1349     "---> splitting |" << theString << "|" <<
1350     endl <<
1351     endl;
1352 #endif
1353 
1354   int theStringSize = theString.size ();
1355 
1356   size_t currentPosition = 0;
1357 
1358 #ifdef DEBUG_SPLITTING
1359   string remainder = theString;
1360 #endif
1361 
1362   int theSeparatorSize = theSeparator.size ();
1363 
1364   map<string, string>::const_iterator i;
1365 
1366   while (1) {
1367     size_t found =
1368       theString.find (theSeparator, currentPosition);
1369 
1370     if (found == string::npos) {
1371       // fetch the last chunk
1372       // we have a last chunk
1373       // from currentPosition to theStringSize
1374       int chunkLength = theStringSize - currentPosition;
1375 
1376       string
1377         chunk =
1378           theString.substr (
1379             currentPosition,
1380             chunkLength);
1381 
1382       chunksList.push_back (
1383         chunk);
1384 
1385 #ifdef DEBUG_SPLITTING
1386       gLogOstream <<
1387         "theStringSize = " << theStringSize <<
1388         endl <<
1389         "currentPosition = " << currentPosition <<
1390         endl <<
1391         "remainder = |" << remainder << "|" <<
1392         endl <<
1393         "chunkLength = " << chunkLength <<
1394         endl <<
1395         "chunk = \"" << chunk << "\"" <<
1396         endl <<
1397         endl;
1398 #endif
1399 
1400       break;
1401     }
1402 
1403     else {
1404       // we have a chunk from currentPosition to found
1405       int chunkLength = found - currentPosition;
1406 
1407       string
1408         chunk =
1409           theString.substr (
1410             currentPosition,
1411             chunkLength);
1412 
1413       // append it to the chunks list
1414       chunksList.push_back (
1415         chunk);
1416 
1417       // advance the cursor
1418       currentPosition +=
1419         chunkLength + theSeparatorSize;
1420 
1421       // there can be an end of line JMI
1422       if (theString [currentPosition] == '\n')
1423         currentPosition++;
1424 
1425 #ifdef DEBUG_SPLITTING
1426       // set remainder
1427       remainder =
1428         theString.substr (
1429           currentPosition);
1430 
1431       gLogOstream <<
1432         "theStringSize = " << theStringSize <<
1433         endl <<
1434         "currentPosition = " << currentPosition <<
1435         endl <<
1436         "remainder = |" << remainder << "|" <<
1437         endl <<
1438         "found = " << found <<
1439         endl <<
1440         "chunkLength = " << chunkLength <<
1441         endl <<
1442         "chunk = \"" << chunk << "\"" <<
1443         endl <<
1444         endl;
1445 #endif
1446     }
1447   } // while
1448 }
1449 
1450 //______________________________________________________________________________
splitRegularStringAtEndOfLines(string theString,list<string> & chunksList)1451 void splitRegularStringAtEndOfLines (
1452   string        theString,
1453   list<string>& chunksList)
1454 {
1455 //#define DEBUG_SPLITTING
1456 
1457 #ifdef DEBUG_SPLITTING
1458   gLogOstream <<
1459     "---> splitting |" << theString << "|" <<
1460     endl <<
1461     endl;
1462 #endif
1463 
1464   splitStringIntoChunks (
1465     theString,
1466     "\n",
1467     chunksList);
1468 
1469     /* JMI
1470   int theStringSize = theString.size ();
1471 
1472   size_t currentPosition = 0;
1473 
1474 #ifdef DEBUG_SPLITTING
1475   string remainder = theString;
1476 #endif
1477 
1478   string lookedFor     = "\n";
1479   int    lookedForSize = lookedFor.size ();
1480 
1481   map<string, string>::const_iterator i;
1482 
1483   while (1) {
1484     size_t found =
1485       theString.find (lookedFor, currentPosition);
1486 
1487     if (found == string::npos) {
1488       // fetch the last chunk
1489       // we have a last chunk
1490       // from currentPosition to theStringSize
1491       int chunkLength = theStringSize - currentPosition;
1492 
1493       string
1494         chunk =
1495           theString.substr (
1496             currentPosition,
1497             chunkLength);
1498 
1499       chunksList.push_back (
1500         chunk);
1501 
1502 #ifdef DEBUG_SPLITTING
1503       gLogOstream <<
1504         "theStringSize = " << theStringSize <<
1505         endl <<
1506         "currentPosition = " << currentPosition <<
1507         endl <<
1508         "remainder = |" << remainder << "|" <<
1509         endl <<
1510         "chunkLength = " << chunkLength <<
1511         endl <<
1512         "chunk = \"" << chunk << "\"" <<
1513         endl <<
1514         endl;
1515 #endif
1516 
1517       break;
1518     }
1519 
1520     else {
1521       // we have a chunk from currentPosition to found
1522       int chunkLength = found - currentPosition;
1523 
1524       string
1525         chunk =
1526           theString.substr (
1527             currentPosition,
1528             chunkLength);
1529 
1530       // append it to the chunks list
1531       chunksList.push_back (
1532         chunk);
1533 
1534       // advance the cursor
1535       currentPosition +=
1536         chunkLength + lookedForSize;
1537 
1538       // there can be an end of line JMI
1539       if (theString [currentPosition] == '\n')
1540         currentPosition++;
1541 
1542 #ifdef DEBUG_SPLITTING
1543       // set remainder
1544       remainder =
1545         theString.substr (
1546           currentPosition);
1547 
1548       gLogOstream <<
1549         "theStringSize = " << theStringSize <<
1550         endl <<
1551         "currentPosition = " << currentPosition <<
1552         endl <<
1553         "remainder = |" << remainder << "|" <<
1554         endl <<
1555         "found = " << found <<
1556         endl <<
1557         "chunkLength = " << chunkLength <<
1558         endl <<
1559         "chunk = \"" << chunk << "\"" <<
1560         endl <<
1561         endl;
1562 #endif
1563     }
1564   } // while
1565   */
1566 }
1567 
1568 //______________________________________________________________________________
splitHTMLStringContainingEndOfLines(string theString,list<string> & chunksList)1569 void splitHTMLStringContainingEndOfLines (
1570   string        theString,
1571   list<string>& chunksList)
1572 {
1573 //#define DEBUG_SPLITTING
1574 
1575 #ifdef DEBUG_SPLITTING
1576   gLogOstream <<
1577     "---> splitting |" << theString << "|" <<
1578     endl <<
1579     endl;
1580 #endif
1581 
1582   int theStringSize = theString.size ();
1583 
1584   map<string, string> conversionMap; // JMI
1585 
1586   conversionMap ["&"] = "&amp;";
1587   conversionMap ["\""] = "&quot;";
1588   conversionMap ["'"] = "&apos;";
1589   conversionMap ["<"] = "&lt;";
1590   conversionMap [">"] = "&gt;";
1591 
1592   size_t currentPosition = 0;
1593 
1594 #ifdef DEBUG_SPLITTING
1595   string remainder = theString;
1596 #endif
1597 
1598 // JMI  string lookedFor     = "&#xd;";
1599   string lookedFor     = "\n";
1600   int    lookedForSize = lookedFor.size ();
1601 
1602   map<string, string>::const_iterator i;
1603 
1604 /*
1605   for (i = conversionMap.begin (); i != conversionMap.end (); ++i) {
1606     string
1607       lookedFor = i->second,
1608       ersatz    = i->first;
1609     // replace all occurrences of lookedFor by ersatz
1610   } // for
1611 */
1612 
1613   while (1) {
1614     size_t found =
1615       theString.find (lookedFor, currentPosition);
1616 
1617     if (found == string::npos) {
1618       // fetch the last chunk
1619       // we have a last chunk
1620       // from currentPosition to theStringSize
1621       int chunkLength = theStringSize - currentPosition;
1622 
1623       string
1624         chunk =
1625           theString.substr (
1626             currentPosition,
1627             chunkLength);
1628 
1629       chunksList.push_back (
1630         chunk);
1631 
1632 #ifdef DEBUG_SPLITTING
1633       gLogOstream <<
1634         "theStringSize = " << theStringSize <<
1635         endl <<
1636         "currentPosition = " << currentPosition <<
1637         endl <<
1638         "remainder = |" << remainder << "|" <<
1639         endl <<
1640         "chunkLength = " << chunkLength <<
1641         endl <<
1642         "chunk = \"" << chunk << "\"" <<
1643         endl <<
1644         endl;
1645 #endif
1646 
1647       break;
1648     }
1649 
1650     else {
1651       // we have a chunk from currentPosition to found
1652       int chunkLength = found - currentPosition;
1653 
1654       string
1655         chunk =
1656           theString.substr (
1657             currentPosition,
1658             chunkLength);
1659 
1660       // append it to the chunks list
1661       chunksList.push_back (
1662         chunk);
1663 
1664       // advance the cursor
1665       currentPosition +=
1666         chunkLength + lookedForSize;
1667 
1668       // there can be an end of line JMI
1669       if (theString [currentPosition] == '\n')
1670         currentPosition++;
1671 
1672 #ifdef DEBUG_SPLITTING
1673       // set remainder
1674       remainder =
1675         theString.substr (
1676           currentPosition);
1677 
1678       gLogOstream <<
1679         "theStringSize = " << theStringSize <<
1680         endl <<
1681         "currentPosition = " << currentPosition <<
1682         endl <<
1683         "remainder = |" << remainder << "|" <<
1684         endl <<
1685         "found = " << found <<
1686         endl <<
1687         "chunkLength = " << chunkLength <<
1688         endl <<
1689         "chunk = \"" << chunk << "\"" <<
1690         endl <<
1691         endl;
1692 #endif
1693     }
1694   } // while
1695 }
1696 
1697 //______________________________________________________________________________
baseName(const string & filename)1698 string baseName (const string &filename)
1699 {
1700   if (! filename.size ()) {
1701       return {};
1702   }
1703 
1704   auto len   = filename.length ();
1705   auto index = filename.find_last_of ("/\\");
1706 
1707   if (index == string::npos) {
1708       return filename;
1709   }
1710 
1711   if (index + 1 >= len) {
1712     len--;
1713     index = filename.substr (0, len).find_last_of ("/\\");
1714 
1715     if (len == 0) {
1716       return filename;
1717     }
1718 
1719     if (index == 0) {
1720       return filename.substr (1, len - 1);
1721     }
1722 
1723     if (index == string::npos) {
1724       return filename.substr (0, len);
1725     }
1726 
1727     return filename.substr (index + 1, len - index - 1);
1728   }
1729 
1730   return filename.substr (index + 1, len - index);
1731 }
1732 
1733 //______________________________________________________________________________
makeSingleWordFromString(const string & theString)1734 string makeSingleWordFromString (const string& theString)
1735 {
1736   string result;
1737 
1738   if (theString.size ()) {
1739     for (
1740       string::const_iterator i = theString.begin ();
1741       i != theString.end ();
1742       i++
1743     ) {
1744       if (isalnum (*i)) {
1745         result.push_back ((*i));
1746       }
1747     } // for
1748   }
1749 
1750   return result;
1751 }
1752 
1753 
1754 }
1755 
1756 /* JMI
1757 //______________________________________________________________________________
1758 class EXP segmentedLinesOstream
1759 {
1760 / * JMI NOT DONE
1761   // in order to avoid spaces at the end of a line,
1762   // an end of segment causes a space to be output later,
1763   // by the next '<<' operator
1764 
1765 --
1766 *
1767 Reference for this class:
1768   https://stackoverflow.com/questions/2212776/overload-handling-of-stdendl
1769 
1770 Usage:
1771   segmentedLinesOstream myStream (std::cout);
1772 
1773   myStream <<
1774     1 << 2 << 3 << std::endl <<
1775     5 << 6 << std::endl <<
1776     7 << 8 << std::endl;
1777 * /
1778 
1779   private:
1780     // segmentedLinesOstream just uses an indentedOstream
1781     indentedOstream&      fIndentedOstream;
1782 
1783     // an end of segment causes a space to be output by the next '<<' operator
1784     bool                  fAtEndOfSegment;
1785 
1786   public:
1787 
1788     // constructor
1789     segmentedLinesOstream (
1790       indentedOstream& indentedOstream)
1791       : fIndentedOstream (indentedOstream)
1792         { fAtEndOfSegment = false; }
1793 
1794     // destructor
1795     virtual ~segmentedLinesOstream ()
1796         {};
1797 
1798     // flush
1799     void                  flush ()
1800                               { fIndentedOstream.flush (); }
1801 
1802     // set and get
1803     indentedOstream&      getIndentedOstream ()
1804                               { return fIndentedOstream; }
1805 
1806     // indentation
1807     indenter&             getIndenter ()
1808                               { return fIndentedOstream.getIndenter (); }
1809 
1810     void                  incrIdentation ()
1811                               { fIndentedOstream.incrIdentation (); }
1812 
1813     void                  decrIdentation ()
1814                               { fIndentedOstream.decrIdentation (); }
1815 
1816     // segments
1817     void                  setAtEndOfSegment (bool value)
1818                               { fAtEndOfSegment = value; }
1819     bool                  getAtEndOfSegment ()
1820                               { return fAtEndOfSegment; }
1821 };
1822 
1823 // '<<' operators to implement segments
1824 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, char ch);
1825 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, int i);
1826 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, unsigned int i);
1827 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, float f);
1828 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, const std::string& str);
1829 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, char * str);
1830 
1831 // the manipulators
1832 segmentedLinesOstream& endline (segmentedLinesOstream& os);
1833 segmentedLinesOstream& endseg (segmentedLinesOstream& os);
1834 */
1835 
1836 
1837 /* JMI
1838   segmentedLinesOstream
1839     testSegmentedLinesOstream (fLogOutputStream);
1840 
1841   fLogOutputStream <<
1842     "getAtEndOfSegment: " <<
1843     booleanAsString (
1844       testSegmentedLinesOstream.getAtEndOfSegment ()) <<
1845     endl;
1846 
1847   testSegmentedLinesOstream.setAtEndOfSegment (true);
1848 
1849   fLogOutputStream <<
1850     "getAtEndOfSegment: " <<
1851     booleanAsString (
1852       testSegmentedLinesOstream.getAtEndOfSegment ()) <<
1853     endl;
1854 
1855   testSegmentedLinesOstream <<
1856     "FOO" << endl; // <<
1857  //   endline;
1858 
1859   testSegmentedLinesOstream.getIndentedOstream () << flush;
1860   */
1861 
1862 
1863 /* JMI
1864 //______________________________________________________________________________
1865 // the manipulators
1866 segmentedLinesOstream& endline (segmentedLinesOstream& os)
1867 {
1868   if (! os.getAtEndOfSegment ()) {
1869     // don't output multiple spaces after a segment
1870     os.setAtEndOfSegment (true);
1871   }
1872 
1873   os.getIndentedOstream () << endl;
1874 
1875   return os;
1876 }
1877 
1878 segmentedLinesOstream& endseg (segmentedLinesOstream& os)
1879 {
1880   if (! os.getAtEndOfSegment ()) {
1881     // don't output multiple spaces after a segment
1882     os.setAtEndOfSegment (true);
1883   }
1884 
1885   return os;
1886 }
1887 
1888 // '<<' operators to implement segments
1889 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, char ch)
1890 {
1891   if (os.getAtEndOfSegment ()) {
1892     os << ' ';
1893     os.setAtEndOfSegment (false);
1894   }
1895 
1896   os.getIndentedOstream () << ch;
1897 
1898   return os;
1899 }
1900 
1901 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, int i)
1902 {
1903   if (os.getAtEndOfSegment ()) {
1904     os << ' ';
1905     os.setAtEndOfSegment (false);
1906   }
1907 
1908   os.getIndentedOstream () << i;
1909 
1910   return os;
1911 }
1912 
1913 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, unsigned int i)
1914 {
1915   if (os.getAtEndOfSegment ()) {
1916     os << ' ';
1917     os.setAtEndOfSegment (false);
1918   }
1919 
1920   os.getIndentedOstream () << i;
1921 
1922   return os;
1923 }
1924 
1925 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, float f)
1926 {
1927   if (os.getAtEndOfSegment ()) {
1928     os << ' ';
1929     os.setAtEndOfSegment (false);
1930   }
1931 
1932   os.getIndentedOstream () << f;
1933 
1934   return os;
1935 }
1936 
1937 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, const string& str)
1938 {
1939   if (os.getAtEndOfSegment ()) {
1940     os << ' ';
1941     os.setAtEndOfSegment (false);
1942   }
1943 
1944   os.getIndentedOstream () << str;
1945 
1946   return os;
1947 }
1948 
1949 EXP segmentedLinesOstream& operator<< (segmentedLinesOstream& os, char * str)
1950 {
1951   if (os.getAtEndOfSegment ()) {
1952     os << ' ';
1953     os.setAtEndOfSegment (false);
1954   }
1955 
1956   os.getIndentedOstream () << str;
1957 
1958   return os;
1959 }
1960 */
1961 
1962