Wtx ~ Wt Extension Library
WtxLib
Util.cpp
1 
2 #include <cmath>
3 #include <algorithm>
4 #include <dirent.h>
5 #include <fstream>
6 #include <iostream>
7 #include <regex>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <locale.h>
11 
12 #include <Wt/WString.h>
13 
14 #include "Util.h"
15 
16 
17 std::string Wtx::json_number_to_string( const std::string & key, const std::string & data )
18 {
30  std::string retVal;
31 
32  /*
33  **
34  **
35  ** +---------------------------------------- first capture start
36  ** | +-------------------------------------- literal " (double quote)
37  ** | | +--------------------------------- literal key (case sensitive)
38  ** | | | +------------------------- literal " (double quote)
39  ** | | | |+------------------------ literal : (colon)
40  ** | | | || +--------------------- space characters
41  ** | | | || |+-------------------- as many as there are
42  ** | | | || ||+------------------- first capture end
43  ** | | | || |||+------------------ second capture start
44  ** | | | || |||| +--------------- get digits
45  ** | | | || |||| | +------------- at least 8 digits
46  ** | | | || |||| | |+------------ as many as there are
47  ** | | | || |||| | || +---------- second capture end
48  ** | | | || |||| | || |
49  ** | | | || |||| | || |
50  ** | | | || |||| | || |
51  ** V V V VV VVVV V VV V */
52  std::regex reg( "(\"" + key + "\":\\s*)(\\d{8,})" );
53  std::regex_replace
54  (
55  std::back_inserter(retVal),
56  data.begin(),
57  data.end(),
58  reg,
59  "$1\"$2\""
60  /* ^ ^^ ^
61  ** | || |
62  ** | || +--------------- literal " (double quote)
63  ** | |+------------------ second capture
64  ** | +------------------- literal " (double quote)
65  ** +---------------------- first capture
66  */
67  );
68 
69  return retVal;
70 
71 }
72 
85 std::string Wtx::makeFileName( const std::string & value )
86 {
87  std::string retVal;
88 
89  /*
90  ** each character is examined individually
91  */
92  for( auto ch : value )
93  {
97  if( isprint( ch ) )
98  {
127  switch( ch )
128  {
129  case '.': break;
130  case ',': break;
131  case '<': retVal += '('; break;
132  case '>': retVal += ')'; break;
133  case ':': retVal += '-'; break;
134  case '"': retVal += '\''; break;
135  case '/': retVal += '-'; break;
136  case '\\': retVal += '-'; break;
137  case '|': break;
138  case '?': break;
139  case '*': break;
140  default: retVal += ch;
141 
142  } // endswitch( ch )
143 
144  } // endif( isprint( ch ) )
145 
146  } // endfor( auto ch : value )
147 
148  return retVal;
149 
150 } // endstd::string Wtx::makeFileName( const std::string & value )
151 
152 
153 int Wtx::system_command( const std::string & cmd, bool show )
154 {
155  int result = system( cmd.c_str() );
156 
157  if( show )
158  std::cout << __FILE__ << ":" << __LINE__ << " " << cmd << std::endl;
159 
160 
161 
162  if( result != 0 )
163  {
164  std::cout << __FILE__ << ":" << __LINE__ << " "
165  << result << " "
166  << cmd
167  << std::endl
168  ;
169  }
170 
171  return result;
172 
173 } // endint Wtx::system_command( const std::string & cmd, bool show )
174 
175 /*
176 ** This function produces a case-insensitive sort of
177 ** the files and folders in a directory. The file
178 ** items are converted to upper-case so that case
179 ** becomes ignored, and then the function uses the
180 ** strverscmp function which causes jan-1, jan-2,
181 ** jan-10 to be sorted in that order, which can
182 ** make a little more logical sense when looking at
183 ** folder names.
184 **
185 ** https://linux.die.net/man/3/scandir
186 **
187 */
188 static int ialphasort( const struct dirent **a, const struct dirent **b )
189 {
190  std::string ua = (*a)-> d_name;
191  std::transform( ua.begin(), ua.end(), ua.begin(), ::toupper );
192 
193  std::string ub = (*b)-> d_name;
194  std::transform( ub.begin(), ub.end(), ub.begin(), ::toupper );
195 
196  return strverscmp( ua.c_str(), ub.c_str() );
197 }
198 
199 
200 
201 std::vector<std::string> Wtx::fileList( const std::string & folder )
202 {
203  std::vector<std::string> retVal;
204 
205  /*
206  ** pull up all the items in this folder
207  **
208  */
209  struct dirent ** namelist;
210  int n = scandir( folder.c_str(), &namelist, 0, ialphasort );
211 
212  if( n > 0 )
213  {
214  /*
215  ** loop through all the items in the folder
216  **
217  */
218  for( int i=0; i< n; i++ )
219  {
220  /*
221  ** pull the folder name from the items list
222  ** and free the original source
223  **
224  */
225  std::string fileName( namelist[i]-> d_name );
226  free( namelist[i] );
227 
228  /*
229  ** single '.' dot items are ignored totally
230  */
231  if( fileName == "." )
232  continue;
233 
234  /*
235  ** make something that represents the full file path
236  **
237  */
238  std::string filePath( folder + "/" + fileName );
239 
240  /*
241  ** the 'fileStat' value contains the following flags
242  ** and status codes. grab the filestat based on the 'stat'
243  ** function call so that the file can be parsed.
244  **
245  ** st_atime
246  ** st_ctime
247  ** st_gid
248  ** st_ino
249  ** st_mtime·
250  ** st_nlink·
251  ** st_mode·
252  ** st_size·
253  ** st_uid·
254  **
255  */
256  struct stat fileStat;
257  int result = stat( filePath.c_str(), &fileStat );
258 
259  /*
260  ** there should always be a result on pulling the
261  ** file stat.
262  */
263  if( result == 0 )
264  {
265  retVal.push_back( fileName );
266  }
267 
268  } // endfor( int i=0; i< n; i++ )
269 
270  free( namelist );
271 
272  } // endif( n > 0 )
273 
274  return retVal;
275 
276 } // endstd::vector<std::string> Wtx::fileList( const std::string & folder )
277 
278 std::vector<std::string> Wtx::findFiles( const std::string & folder, const std::string & match )
279 {
280  std::vector<std::string> retVal;
281 
282  for( auto fileName : fileList( folder ) )
283  if( fileName.find(match) != std::string::npos )
284  retVal.push_back( fileName );
285 
286  return retVal;
287 }
288 
289 bool Wtx::fileExists( const std::string & fileName )
290 {
291  std::ifstream f( fileName.c_str() );
292  return f.good();
293 }
294 
295 int Wtx::stoi( const std::string & value )
296 {
297  try
298  {
299  int id = std::stoi(value);
300  return id;
301  }
302  catch(...)
303  {
304 // std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << "::value='" << value << "'" << std::endl;
305  }
306 
307  return 0;
308 
309 }
310 
311 std::string Wtx::itos( int value )
312 {
313  return
314  Wt::WString("{1}")
315  .arg( value )
316  .toUTF8()
317  ;
318 }
319 
320 double Wtx::stof( const std::string & value )
321 {
322  try
323  {
324  std::string v;
325  for( auto c : value )
326  if( isdigit(c) || c == '.' )
327  v.push_back(c);
328 
329  if( v.length() > 0 )
330  {
331  double id = std::stod(v);
332  return id;
333  }
334 
335  }
336  catch(...)
337  {
338  }
339 
340  return 0;
341 
342 }
343 
344 std::string Wtx::ftos( double value, int decimals )
345 {
346  char buffer[256];
347 
348  snprintf( buffer, sizeof(buffer), "%.*f", decimals, value );
349 
350  return std::string(buffer);
351 
352 }
353 
354 std::string Wtx::ftos( double value, const std::string & suffix, int decimals )
355 {
356  char buffer[256];
357 
358  snprintf( buffer, sizeof(buffer), "%.*f%s", decimals, value, suffix.data() );
359 
360  return std::string(buffer);
361 
362 }
363 
364 std::string Wtx::ftos( const std::string & prefix, double value, int decimals )
365 {
366  char buffer[256];
367 
368  snprintf( buffer, sizeof(buffer), "%s%.*f", prefix.data(), decimals, value );
369 
370  return std::string(buffer);
371 
372 }
373 
374 std::string Wtx::ftom( double value, int decimals )
375 {
376  char buffer[256];
377 
378  std::setlocale( LC_ALL, "" );
379  snprintf( buffer, sizeof(buffer), "%'.*f", decimals, value );
380 
381  return std::string(buffer);
382 
383 }
384 
385 std::string Wtx::ftom( const std::string & prefix, double value, int decimals )
386 {
387  char buffer[256];
388 
389  std::setlocale( LC_ALL, "" );
390  snprintf( buffer, sizeof(buffer), "%s%'.*f", prefix.data(), decimals, value );
391 
392  return std::string(buffer);
393 
394 }
395 
396 bool Wtx::ends_with( const std::string & value, const std::string & ending )
397 {
398  if( ending.size() > value.size() )
399  return false;
400 
401  return std::equal( ending.rbegin(), ending.rend(), value.rbegin() );
402 }
403 
404 std::string Wtx::append( const std::string & s, const std::string & append, const std::string & separator )
405 {
406  std::string retVal = s;
407 
408  /*
409  ** only put the separator on if there is already data, and...
410  */
411  if( retVal != "" )
412  {
413  /*
414  ** ...and if the end of the string doesn't already have
415  ** the separator on it
416  **
417  */
418  if( !ends_with( retVal, separator ) )
419  {
420  retVal += separator;
421  }
422 
423  } // endif( retVal != "" )
424 
425  retVal += append;
426 
427  return retVal;
428 
429 } //endstd::string Wtx::append( const std::string & s, const std::string & append, const std::string & separator )
430 
431 std::string Wtx::prepend( const std::string & s, int length, char pad )
432 {
433  std::string retVal = s;
434 
435  while( retVal.length() < length )
436  retVal = pad + retVal;
437 
438  return retVal;
439 }
440 
441 std::string Wtx::ucase( const std::string & value )
442 {
443  std::string retVal = value;
444  std::transform( retVal.begin(), retVal.end(), retVal.begin(), ::toupper );
445  return retVal;
446 }
447 
448 std::string Wtx::lcase( const std::string & value )
449 {
450  std::string retVal = value;
451  std::transform( retVal.begin(), retVal.end(), retVal.begin(), ::tolower );
452  return retVal;
453 }
454 
455 int Wtx::roundUp( float value )
456 {
457  int v = value;
458  if( v < value )
459  v++;
460 
461  return v;
462 }
463 
464 int Wtx::roundDown( float value )
465 {
466  return value;
467 }
468 
469 float Wtx::roundCurrency( float value )
470 {
471  float retVal = value * 100;
472 
473  retVal = round(retVal);
474 
475  retVal /= 100;
476 
477  return retVal;
478 }
479 
480 std::string Wtx::replace( const std::string & string, const std::string & before, const std::string & after )
481 {
482  std::string retVal = string;
483 
484  size_t start_pos = 0;
485  while( (start_pos = retVal.find( before, start_pos )) != std::string::npos )
486  {
487  retVal.replace( start_pos, before.length(), after );
488  start_pos += after.length(); // Handles case where 'to' is a substring of 'from'
489  }
490 
491  return retVal;
492 }
493 
494 void Wtx::ltrim(std::string &s)
495 {
496  s.erase
497  (
498  s.begin(),
499  std::find_if
500  (
501  s.begin(),
502  s.end(),
503  [](int ch)
504  {
505  return !std::isspace(ch);
506  }
507  )
508  );
509 }
510 
511 // trim from end (in place)
512 void Wtx::rtrim(std::string &s)
513 {
514  s.erase
515  (
516  std::find_if
517  (
518  s.rbegin(),
519  s.rend(),
520  [](int ch)
521  {
522  return !std::isspace(ch);
523  })
524  .base(),
525  s.end()
526  );
527 }
528 
529 // trim from both ends (in place)
530 void Wtx::trim(std::string &s)
531 {
532  ltrim(s);
533  rtrim(s);
534 }
535 
536 // trim from start (copying)
537 std::string Wtx::ltrim_copy(std::string s)
538 {
539  ltrim(s);
540  return s;
541 }
542 
543 // trim from end (copying)
544 std::string Wtx::rtrim_copy(std::string s)
545 {
546  rtrim(s);
547  return s;
548 }
549 
550 // trim from both ends (copying)
551 std::string Wtx::trim_copy(std::string s)
552 {
553  trim(s);
554  return s;
555 }
556 
557 Wtx::Util::Money::ItemDelegate::ItemDelegate( Wtx::Dbo::Session * s )
558 : m_session(s)
559 {
560 }
561 
562 std::unique_ptr<Wt::WWidget> Wtx::Util::Money::ItemDelegate::update( Wt::WWidget * widget, const Wt::WModelIndex & index, Wt::WFlags< Wt::ViewItemRenderFlag > flags )
563 {
564  auto w = Wt::WItemDelegate::update( widget, index, flags );
565 
566  auto text = dynamic_cast<Wt::WText *>(w.get());
567  if( text )
568  {
569  text-> setText( Wtx::ftos( Wtx::roundCurrency( Wtx::stof(text-> text().toUTF8()) ) ) );
570 
571  } // endif( text )
572 
573 
574  return std::move(w);
575 
576 } // endstd::unique_ptr<Wt::WWidget> Wtx::Sys::Lookup::Delegate::update( Wt::WWidget * widget, const Wt::WModelIndex & index, Wt::WFlags< Wt::ViewItemRenderFlag > flags )
577 
578 
579 
580 Wt::WItemDelegate * Wtx::Util::Money::ItemDelegate::create( Wtx::Dbo::Session * s )
581 {
582  return new Wtx::Util::Money::ItemDelegate(s);
583 }
584 
585 
586 enum class CSVState
587 {
588  UnquotedField,
589  QuotedField,
590  QuotedQuote
591 };
592 
593 std::vector<std::string> Wtx::readCSVRow( const std::string & row )
594 {
595  CSVState state = CSVState::UnquotedField;
596  std::vector<std::string> fields {""};
597  size_t i = 0; // index of the current field
598  for( char c : row )
599  {
600  switch( state )
601  {
602  case CSVState::UnquotedField:
603  {
604  switch( c )
605  {
606  case ',': // end of field
607  {
608  fields.push_back("");
609  i++;
610  break;
611  }
612 
613  case '"':
614  {
615  state = CSVState::QuotedField;
616  break;
617  }
618 
619  default:
620  {
621  fields[i].push_back(c);
622  break;
623  }
624 
625  } // endswitch( c )
626 
627  break;
628 
629  } // endcase CSVState::UnquotedField:
630 
631  case CSVState::QuotedField:
632  {
633  switch( c )
634  {
635  case '"':
636  {
637  state = CSVState::QuotedQuote;
638  break;
639  }
640 
641  default:
642  {
643  fields[i].push_back(c);
644  break;
645  }
646 
647  } // endswitch( c )
648 
649  break;
650 
651  } // endcase CSVState::QuotedField:
652 
653  case CSVState::QuotedQuote:
654  {
655  switch( c )
656  {
657  case ',': // , after closing quote
658  {
659  fields.push_back("");
660  i++;
661  state = CSVState::UnquotedField;
662  break;
663  }
664 
665  case '"': // "" -> "
666  {
667  fields[i].push_back('"');
668  state = CSVState::QuotedField;
669  break;
670  }
671 
672  default: // end of quote
673  {
674  state = CSVState::UnquotedField;
675  break;
676  }
677 
678  } // endswitch( c )
679 
680  break;
681 
682  } // endcase CSVState::QuotedQuote:
683 
684  } // endswitch( state )
685 
686  } // endfor( char c : row )
687 
688  return fields;
689 
690 } // endstd::vector<std::string> readCSVRow( const std::string & row )
691 
692  #ifdef NEVER
693  std::vector<std::vector<std::string>> readCSV(std::istream &in) {
695  std::vector<std::vector<std::string>> table;
696  std::string row;
697  while (!in.eof()) {
698  std::getline(in, row);
699  if (in.bad() || in.fail()) {
700  break;
701  }
702  auto fields = readCSVRow(row);
703  table.push_back(fields);
704  }
705  return table;
706 }
707  #endif
708 
709 
710 bool Wtx::feq( double a, double b, double epsilon, bool trace )
711 {
712  bool retVal = fabs( a - b ) < epsilon;
713 
714  if( trace )
715  std::cout << __FILE__ << ":" << __LINE__
716  << " retv:" << std::fixed << retVal
717  << " eps:" << std::fixed << epsilon
718  << " fabs:" << std::fixed << fabs( a - b )
719  << " a:" << std::fixed << a
720  << " b:" << std::fixed << b
721  << std::endl
722  ;
723 
724  return retVal;
725 }
726 
727 /*
728 ** this will strip the leading and trailing <div> from a template html stream.
729 **
730 */
731 std::string Wtx::to_string( Wt::WTemplate & templt )
732 {
733  std::string retVal;
734 
735  std::stringstream ss;
736  templt.htmlText( ss );
737 
738  std::string junk;
739  getline( ss, junk );
740 
741  while( !ss.eof() )
742  {
743  std::string line;
744  getline( ss, line );
745 
746  if( !ss.eof() )
747  retVal += line;
748 
749  }
750 
751  return retVal;
752 }
753 
754 
755 std::string Wtx::to_string( Wt::WTemplate * templt )
756 {
757  return to_string( *templt );
758 }
759 
760 bool Wtx::to_htmlfile( Wt::WTemplate & templt, const std::string & folderName, const std::string & fileName )
761 {
762  std::ofstream ofs( folderName + fileName, std::ofstream::out );
763  ofs << to_string( templt );
764  return true;
765 }
766 
767 bool Wtx::to_htmlfile( Wt::WTemplate * templt, const std::string & folderName, const std::string & fileName )
768 {
769  to_htmlfile( *templt, folderName, fileName );
770  return true;
771 }
772 
773 
774 std::string Wtx::hexDump( const std::string & string, int start, int end )
775 {
776  std::stringstream rv;
777 
778  char buffer[100];
779  for( unsigned int i=0; i<string.length(); i += 16 )
780  {
781  std::string adrLine;
782  std::string hexLine;
783  std::string ascLine;
784 
785  sprintf( buffer, "%04x: ", i );
786  adrLine = std::string(buffer);
787 
788  for( int j=0; j<16; j++ )
789  {
790  if( i+j < string.length() )
791  {
792  sprintf( buffer, "%02x ", (string.at(i+j) & 0xff) );
793  hexLine += std::string(buffer);
794 
795  if( std::isprint( string.at(i+j) ) )
796  {
797  sprintf( buffer, "%c", string.at(i+j) );
798  ascLine += std::string(buffer);
799  }
800  else
801  {
802  ascLine += ".";
803  }
804  }
805  else
806  {
807  hexLine += "xx ";
808  ascLine += ".";
809  }
810 
811  } // endfor( int j=0; j<16; j++ )
812 
813  bool showline = false;
814  if( start == -1 && end == -1 )
815  showline = true;
816 
817  else
818  if( (start > -1 && i >= start)
819  && (end > -1 && i <= end)
820  )
821  showline = true;
822 
823  if( showline )
824  rv
825  << adrLine
826  << hexLine
827  << ascLine
828  << std::endl
829  ;
830 
831  } // endfor( int i=0; i<string.length(); i += 16 )
832 
833  return rv.str();
834 
835 } // endstd::string Wtx::hexDump( const std::string & string )
836 
837 const Wtx::CharConv_t Wtx::g_iso8859Conv[256] =
838 {
839 // dec hex sym html utf8 pdf description
840  { /* 0 00 */ "NUL", nullptr, nullptr, nullptr, "Null char" },
841  { /* 1 01 */ "SOH", nullptr, nullptr, nullptr, "Start of Heading" },
842  { /* 2 02 */ "STX", nullptr, nullptr, nullptr, "Start of Text" },
843  { /* 3 03 */ "ETX", nullptr, nullptr, nullptr, "End of Text" },
844  { /* 4 04 */ "EOT", nullptr, nullptr, nullptr, "End of Transmission" },
845  { /* 5 05 */ "ENQ", nullptr, nullptr, nullptr, "Enquiry" },
846  { /* 6 06 */ "ACK", nullptr, nullptr, nullptr, "Acknowledgment" },
847  { /* 7 07 */ "BEL", nullptr, nullptr, nullptr, "Bell" },
848  { /* 8 08 */ "BS", nullptr, nullptr, nullptr, "Back Space" },
849  { /* 9 09 */ "HT", nullptr, nullptr, nullptr, "Horizontal Tab" },
850  { /* 10 0A */ "LF", "<br />", nullptr, nullptr, "Line Feed" },
851  { /* 11 0B */ "VT", nullptr, nullptr, nullptr, "Vertical Tab" },
852  { /* 12 0C */ "FF", nullptr, nullptr, nullptr, "Form Feed" },
853  { /* 13 0D */ "CR", nullptr, nullptr, nullptr, "Carriage Return" },
854  { /* 14 0E */ "SO", nullptr, nullptr, nullptr, "Shift Out / X-On" },
855  { /* 15 0F */ "SI", nullptr, nullptr, nullptr, "Shift In / X-Off" },
856  { /* 16 10 */ "DLE", nullptr, nullptr, nullptr, "Data Line Escape" },
857  { /* 17 11 */ "DC1", nullptr, nullptr, nullptr, "Device Control 1 (oft. XON)" },
858  { /* 18 12 */ "DC2", nullptr, nullptr, nullptr, "Device Control 2" },
859  { /* 19 13 */ "DC3", nullptr, nullptr, nullptr, "Device Control 3 (oft. XOFF)" },
860  { /* 20 14 */ "DC4", nullptr, nullptr, nullptr, "Device Control 4" },
861  { /* 21 15 */ "NAK", nullptr, nullptr, nullptr, "Negative Acknowledgement" },
862  { /* 22 16 */ "SYN", nullptr, nullptr, nullptr, "Synchronous Idle" },
863  { /* 23 17 */ "ETB", nullptr, nullptr, nullptr, "End of Transmit Block" },
864  { /* 24 18 */ "CAN", nullptr, nullptr, nullptr, "Cancel" },
865  { /* 25 19 */ "EM", nullptr, nullptr, nullptr, "End of Medium" },
866  { /* 26 1A */ "SUB", nullptr, nullptr, nullptr, "Substitute" },
867  { /* 27 1B */ "ESC", nullptr, nullptr, nullptr, "Escape" },
868  { /* 28 1C */ "FS", nullptr, nullptr, nullptr, "File Separator" },
869  { /* 29 1D */ "GS", nullptr, nullptr, nullptr, "Group Separator" },
870  { /* 30 1E */ "RS", nullptr, nullptr, nullptr, "Record Separator" },
871  { /* 31 1F */ "US", nullptr, nullptr, nullptr, "Unit Separator" },
872  { /* 32 20 */ " ", nullptr, nullptr, nullptr, "Space" },
873  { /* 33 21 */ "!", nullptr, nullptr, nullptr, "Exclamation mark" },
874  { /* 34 22 */ "\"", "&quot;", nullptr, nullptr, "Double quotes (or speech marks)" },
875  { /* 35 23 */ "#", nullptr, nullptr, nullptr, "Number" },
876  { /* 36 24 */ "$", nullptr, nullptr, nullptr, "Dollar" },
877  { /* 37 25 */ "%", nullptr, nullptr, nullptr, "Procenttecken" },
878  { /* 38 26 */ "&", "&amp;", nullptr, nullptr, "Ampersand" },
879  { /* 39 27 */ "'", nullptr, nullptr, nullptr, "Single quote" },
880  { /* 40 28 */ "(", nullptr, nullptr, nullptr, "Open parenthesis (or open bracket)" },
881  { /* 41 29 */ ")", nullptr, nullptr, nullptr, "Close parenthesis (or close bracket)" },
882  { /* 42 2A */ "*", nullptr, nullptr, nullptr, "Asterisk" },
883  { /* 43 2B */ "+", nullptr, nullptr, nullptr, "Plus" },
884  { /* 44 2C */ ",", nullptr, nullptr, nullptr, "Comma" },
885  { /* 45 2D */ "-", nullptr, nullptr, nullptr, "Hyphen" },
886  { /* 46 2E */ ".", nullptr, nullptr, nullptr, "Period, dot or full stop" },
887  { /* 47 2F */ "/", nullptr, nullptr, nullptr, "Slash or divide" },
888  { /* 48 30 */ "0", nullptr, nullptr, nullptr, "Zero" },
889  { /* 49 31 */ "1", nullptr, nullptr, nullptr, "One" },
890  { /* 50 32 */ "2", nullptr, nullptr, nullptr, "Two" },
891  { /* 51 33 */ "3", nullptr, nullptr, nullptr, "Three" },
892  { /* 52 34 */ "4", nullptr, nullptr, nullptr, "Four" },
893  { /* 53 35 */ "5", nullptr, nullptr, nullptr, "Five" },
894  { /* 54 36 */ "6", nullptr, nullptr, nullptr, "Six" },
895  { /* 55 37 */ "7", nullptr, nullptr, nullptr, "Seven" },
896  { /* 56 38 */ "8", nullptr, nullptr, nullptr, "Eight" },
897  { /* 57 39 */ "9", nullptr, nullptr, nullptr, "Nine" },
898  { /* 58 3A */ ":", nullptr, nullptr, nullptr, "Colon" },
899  { /* 59 3B */ ";", nullptr, nullptr, nullptr, "Semicolon" },
900  { /* 60 3C */ "<", "&lt;", nullptr, nullptr, "Less than (or open angled bracket)" },
901  { /* 61 3D */ "=", nullptr, nullptr, nullptr, "Equals" },
902  { /* 62 3E */ ">", "&gt;", nullptr, nullptr, "Greater than (or close angled bracket)" },
903  { /* 63 3F */ "?", nullptr, nullptr, nullptr, "Question mark" },
904  { /* 64 40 */ "@", nullptr, nullptr, nullptr, "At symbol" },
905  { /* 65 41 */ "A", nullptr, nullptr, nullptr, "Uppercase A" },
906  { /* 66 42 */ "B", nullptr, nullptr, nullptr, "Uppercase B" },
907  { /* 67 43 */ "C", nullptr, nullptr, nullptr, "Uppercase C" },
908  { /* 68 44 */ "D", nullptr, nullptr, nullptr, "Uppercase D" },
909  { /* 69 45 */ "E", nullptr, nullptr, nullptr, "Uppercase E" },
910  { /* 70 46 */ "F", nullptr, nullptr, nullptr, "Uppercase F" },
911  { /* 71 47 */ "G", nullptr, nullptr, nullptr, "Uppercase G" },
912  { /* 72 48 */ "H", nullptr, nullptr, nullptr, "Uppercase H" },
913  { /* 73 49 */ "I", nullptr, nullptr, nullptr, "Uppercase I" },
914  { /* 74 4A */ "J", nullptr, nullptr, nullptr, "Uppercase J" },
915  { /* 75 4B */ "K", nullptr, nullptr, nullptr, "Uppercase K" },
916  { /* 76 4C */ "L", nullptr, nullptr, nullptr, "Uppercase L" },
917  { /* 77 4D */ "M", nullptr, nullptr, nullptr, "Uppercase M" },
918  { /* 78 4E */ "N", nullptr, nullptr, nullptr, "Uppercase N" },
919  { /* 79 4F */ "O", nullptr, nullptr, nullptr, "Uppercase O" },
920  { /* 80 50 */ "P", nullptr, nullptr, nullptr, "Uppercase P" },
921  { /* 81 51 */ "Q", nullptr, nullptr, nullptr, "Uppercase Q" },
922  { /* 82 52 */ "R", nullptr, nullptr, nullptr, "Uppercase R" },
923  { /* 83 53 */ "S", nullptr, nullptr, nullptr, "Uppercase S" },
924  { /* 84 54 */ "T", nullptr, nullptr, nullptr, "Uppercase T" },
925  { /* 85 55 */ "U", nullptr, nullptr, nullptr, "Uppercase U" },
926  { /* 86 56 */ "V", nullptr, nullptr, nullptr, "Uppercase V" },
927  { /* 87 57 */ "W", nullptr, nullptr, nullptr, "Uppercase W" },
928  { /* 88 58 */ "X", nullptr, nullptr, nullptr, "Uppercase X" },
929  { /* 89 59 */ "Y", nullptr, nullptr, nullptr, "Uppercase Y" },
930  { /* 90 5A */ "Z", nullptr, nullptr, nullptr, "Uppercase Z" },
931  { /* 91 5B */ "[", nullptr, nullptr, nullptr, "Opening bracket" },
932  { /* 92 5C */ "\\", nullptr, nullptr, nullptr, "Backslash" },
933  { /* 93 5D */ "]", nullptr, nullptr, nullptr, "Closing bracket" },
934  { /* 94 5E */ "^", nullptr, nullptr, nullptr, "Caret - circumflex" },
935  { /* 95 5F */ "_", nullptr, nullptr, nullptr, "Underscore" },
936  { /* 96 60 */ "`", nullptr, nullptr, nullptr, "Grave accent" },
937  { /* 97 61 */ "a", nullptr, nullptr, nullptr, "Lowercase a" },
938  { /* 98 62 */ "b", nullptr, nullptr, nullptr, "Lowercase b" },
939  { /* 99 63 */ "c", nullptr, nullptr, nullptr, "Lowercase c" },
940  { /* 100 64 */ "d", nullptr, nullptr, nullptr, "Lowercase d" },
941  { /* 101 65 */ "e", nullptr, nullptr, nullptr, "Lowercase e" },
942  { /* 102 66 */ "f", nullptr, nullptr, nullptr, "Lowercase f" },
943  { /* 103 67 */ "g", nullptr, nullptr, nullptr, "Lowercase g" },
944  { /* 104 68 */ "h", nullptr, nullptr, nullptr, "Lowercase h" },
945  { /* 105 69 */ "i", nullptr, nullptr, nullptr, "Lowercase i" },
946  { /* 106 6A */ "j", nullptr, nullptr, nullptr, "Lowercase j" },
947  { /* 107 6B */ "k", nullptr, nullptr, nullptr, "Lowercase k" },
948  { /* 108 6C */ "l", nullptr, nullptr, nullptr, "Lowercase l" },
949  { /* 109 6D */ "m", nullptr, nullptr, nullptr, "Lowercase m" },
950  { /* 110 6E */ "n", nullptr, nullptr, nullptr, "Lowercase n" },
951  { /* 111 6F */ "o", nullptr, nullptr, nullptr, "Lowercase o" },
952  { /* 112 70 */ "p", nullptr, nullptr, nullptr, "Lowercase p" },
953  { /* 113 71 */ "q", nullptr, nullptr, nullptr, "Lowercase q" },
954  { /* 114 72 */ "r", nullptr, nullptr, nullptr, "Lowercase r" },
955  { /* 115 73 */ "s", nullptr, nullptr, nullptr, "Lowercase s" },
956  { /* 116 74 */ "t", nullptr, nullptr, nullptr, "Lowercase t" },
957  { /* 117 75 */ "u", nullptr, nullptr, nullptr, "Lowercase u" },
958  { /* 118 76 */ "v", nullptr, nullptr, nullptr, "Lowercase v" },
959  { /* 119 77 */ "w", nullptr, nullptr, nullptr, "Lowercase w" },
960  { /* 120 78 */ "x", nullptr, nullptr, nullptr, "Lowercase x" },
961  { /* 121 79 */ "y", nullptr, nullptr, nullptr, "Lowercase y" },
962  { /* 122 7A */ "z", nullptr, nullptr, nullptr, "Lowercase z" },
963  { /* 123 7B */ "{", nullptr, nullptr, nullptr, "Opening brace" },
964  { /* 124 7C */ "|", nullptr, nullptr, nullptr, "Vertical bar" },
965  { /* 125 7D */ "}", nullptr, nullptr, nullptr, "Closing brace" },
966  { /* 126 7E */ "~", nullptr, nullptr, nullptr, "Equivalency sign - tilde" },
967  { /* 127 7F */ "DEL", nullptr, nullptr, nullptr, "Delete" },
968 
969 // The table below is according to ISO 8859-1, also called ISO Latin-1. Codes 129-159 contain the Microsoft® Windows Latin-1 extended characters.
970 // dec hex sym html utf8 pdf description
971  { /* 128 80 */ "€", "&euro;", nullptr, nullptr, "Euro sign" },
972  { /* 129 81 */ nullptr, nullptr, nullptr, nullptr, nullptr },
973  { /* 130 82 */ "‚", "&sbquo;", nullptr, nullptr, "Single low-9 quotation mark" },
974  { /* 131 83 */ "ƒ", "&fnof;", nullptr, nullptr, "Latin small letter f with hook" },
975  { /* 132 84 */ "„", "&bdquo;", nullptr, nullptr, "Double low-9 quotation mark" },
976  { /* 133 85 */ "…", "&hellip;", nullptr, nullptr, "Horizontal ellipsis" },
977  { /* 134 86 */ "†", "&dagger;", nullptr, nullptr, "Dagger" },
978  { /* 135 87 */ "‡", "&Dagger;", nullptr, nullptr, "Double dagger" },
979  { /* 136 88 */ "ˆ", "&circ;", nullptr, nullptr, "Modifier letter circumflex accent" },
980  { /* 137 89 */ "‰", "&permil;", nullptr, nullptr, "Per mille sign" },
981  { /* 138 8A */ "Š", "&Scaron;", nullptr, nullptr, "Latin capital letter S with caron" },
982  { /* 139 8B */ "‹", "&lsaquo;", nullptr, nullptr, "Single left-pointing angle quotation" },
983  { /* 140 8C */ "Œ", "&OElig;", nullptr, nullptr, "Latin capital ligature OE" },
984  { /* 141 8D */ nullptr, nullptr, nullptr, nullptr, nullptr },
985  { /* 142 8E */ "Ž", nullptr, nullptr, nullptr, "Latin captial letter Z with caron" },
986  { /* 143 8F */ nullptr, nullptr, nullptr, nullptr, nullptr },
987  { /* 144 90 */ nullptr, nullptr, nullptr, nullptr, nullptr },
988  { /* 145 91 */ "‘", "&lsquo;", nullptr, "'", "Left single quotation mark" },
989  { /* 146 92 */ "’", "&rsquo;", nullptr, "'", "Right single quotation mark" },
990  { /* 147 93 */ "“", "&ldquo;", "\xe2\x80\x9c", "\"", "Left double quotation mark" },
991  { /* 148 94 */ "”", "&rdquo;", "\xe2\x80\x9d", "\"", "Right double quotation mark" },
992  { /* 149 95 */ "•", "&bull;", nullptr, nullptr, "Bullet" },
993  { /* 150 96 */ "–", "&ndash;", nullptr, "-", "En dash" },
994  { /* 151 97 */ "—", "&mdash;", nullptr, "-", "Em dash" },
995  { /* 152 98 */ "˜", "&tilde;", nullptr, "~", "Small tilde" },
996  { /* 153 99 */ "™", "&trade;", nullptr, "tm", "Trade mark sign" },
997  { /* 154 9A */ "š", "&scaron;", nullptr, nullptr, "Latin small letter S with caron" },
998  { /* 155 9B */ "›", "&rsaquo;", nullptr, nullptr, "Single right-pointing angle quotation mark" },
999  { /* 156 9C */ "œ", "&oelig;", nullptr, nullptr, "Latin small ligature oe" },
1000  { /* 157 9D */ nullptr, nullptr, nullptr, nullptr, nullptr },
1001  { /* 158 9E */ "ž", nullptr, nullptr, nullptr, "Latin small letter z with caron" },
1002  { /* 159 9F */ "Ÿ", "&yuml;", nullptr, nullptr, "Latin capital letter Y with diaeresis" },
1003  { /* 160 A0 */ " ", "&nbsp;", nullptr, nullptr, "Non-breaking space" },
1004  { /* 161 A1 */ "¡", "&iexcl;", nullptr, nullptr, "Inverted exclamation mark" },
1005  { /* 162 A2 */ "¢", "&cent;", nullptr, nullptr, "Cent sign" },
1006  { /* 163 A3 */ "£", "&pound;", nullptr, "#", "Pound sign" },
1007  { /* 164 A4 */ "¤", "&curren;", nullptr, nullptr, "Currency sign" },
1008  { /* 165 A5 */ "¥", "&yen;", nullptr, nullptr, "Yen sign" },
1009  { /* 166 A6 */ "¦", "&brvbar;", nullptr, nullptr, "Pipe, Broken vertical bar" },
1010  { /* 167 A7 */ "§", "&sect;", nullptr, nullptr, "Section sign" },
1011  { /* 168 A8 */ "¨", "&uml;", nullptr, nullptr, "Spacing diaeresis - umlaut" },
1012  { /* 169 A9 */ "©", "&copy;", nullptr, nullptr, "Copyright sign" },
1013  { /* 170 AA */ "ª", "&ordf;", nullptr, nullptr, "Feminine ordinal indicator" },
1014  { /* 171 AB */ "«", "&laquo;", nullptr, nullptr, "Left double angle quotes" },
1015  { /* 172 AC */ "¬", "&not;", nullptr, nullptr, "Not sign" },
1016  { /* 173 AD */ "­", "&shy;", nullptr, nullptr, "Soft hyphen" },
1017  { /* 174 AE */ "®", "&reg;", nullptr, nullptr, "Registered trade mark sign" },
1018  { /* 175 AF */ "¯", "&macr;", nullptr, nullptr, "Spacing macron - overline" },
1019  { /* 176 B0 */ "°", "&deg;", nullptr, nullptr, "Degree sign" },
1020  { /* 177 B1 */ "±", "&plusmn;", nullptr, nullptr, "Plus-or-minus sign" },
1021  { /* 178 B2 */ "²", "&sup2;", nullptr, nullptr, "Superscript two - squared" },
1022  { /* 179 B3 */ "³", "&sup3;", nullptr, nullptr, "Superscript three - cubed" },
1023  { /* 180 B4 */ "´", "&acute;", nullptr, nullptr, "Acute accent - spacing acute" },
1024  { /* 181 B5 */ "µ", "&micro;", nullptr, nullptr, "Micro sign" },
1025  { /* 182 B6 */ "¶", "&para;", nullptr, nullptr, "Pilcrow sign - paragraph sign" },
1026  { /* 183 B7 */ "·", "&middot;", nullptr, nullptr, "Middle dot - Georgian comma" },
1027  { /* 184 B8 */ "¸", "&cedil;", nullptr, nullptr, "Spacing cedilla" },
1028  { /* 185 B9 */ "¹", "&sup1;", nullptr, nullptr, "Superscript one" },
1029  { /* 186 BA */ "º", "&ordm;", nullptr, nullptr, "Masculine ordinal indicator" },
1030  { /* 187 BB */ "»", "&raquo;", nullptr, nullptr, "Right double angle quotes" },
1031  { /* 188 BC */ "¼", "&frac14;", nullptr, nullptr, "Fraction one quarter" },
1032  { /* 189 BD */ "½", "&frac12;", nullptr, nullptr, "Fraction one half" },
1033  { /* 190 BE */ "¾", "&frac34;", nullptr, nullptr, "Fraction three quarters" },
1034  { /* 191 BF */ "¿", "&iquest;", nullptr, nullptr, "Inverted question mark" },
1035  { /* 192 C0 */ "À", "&Agrave;", nullptr, nullptr, "Latin capital letter A with grave" },
1036  { /* 193 C1 */ "Á", "&Aacute;", nullptr, nullptr, "Latin capital letter A with acute" },
1037  { /* 194 C2 */ "Â", "&Acirc;", nullptr, nullptr, "Latin capital letter A with circumflex" },
1038  { /* 195 C3 */ "Ã", "&Atilde;", nullptr, nullptr, "Latin capital letter A with tilde" },
1039  { /* 196 C4 */ "Ä", "&Auml;", nullptr, nullptr, "Latin capital letter A with diaeresis" },
1040  { /* 197 C5 */ "Å", "&Aring;", nullptr, nullptr, "Latin capital letter A with ring above" },
1041  { /* 198 C6 */ "Æ", "&AElig;", nullptr, nullptr, "Latin capital letter AE" },
1042  { /* 199 C7 */ "Ç", "&Ccedil;", nullptr, nullptr, "Latin capital letter C with cedilla" },
1043  { /* 200 C8 */ "È", "&Egrave;", nullptr, nullptr, "Latin capital letter E with grave" },
1044  { /* 201 C9 */ "É", "&Eacute;", nullptr, nullptr, "Latin capital letter E with acute" },
1045  { /* 202 CA */ "Ê", "&Ecirc;", nullptr, nullptr, "Latin capital letter E with circumflex" },
1046  { /* 203 CB */ "Ë", "&Euml;", nullptr, nullptr, "Latin capital letter E with diaeresis" },
1047  { /* 204 CC */ "Ì", "&Igrave;", nullptr, nullptr, "Latin capital letter I with grave" },
1048  { /* 205 CD */ "Í", "&Iacute;", nullptr, nullptr, "Latin capital letter I with acute" },
1049  { /* 206 CE */ "Î", "&Icirc;", nullptr, nullptr, "Latin capital letter I with circumflex" },
1050  { /* 207 CF */ "Ï", "&Iuml;", nullptr, nullptr, "Latin capital letter I with diaeresis" },
1051  { /* 208 D0 */ "Ð", "&ETH;", nullptr, nullptr, "Latin capital letter ETH" },
1052  { /* 209 D1 */ "Ñ", "&Ntilde;", nullptr, nullptr, "Latin capital letter N with tilde" },
1053  { /* 210 D2 */ "Ò", "&Ograve;", nullptr, nullptr, "Latin capital letter O with grave" },
1054  { /* 211 D3 */ "Ó", "&Oacute;", nullptr, nullptr, "Latin capital letter O with acute" },
1055  { /* 212 D4 */ "Ô", "&Ocirc;", nullptr, nullptr, "Latin capital letter O with circumflex" },
1056  { /* 213 D5 */ "Õ", "&Otilde;", nullptr, nullptr, "Latin capital letter O with tilde" },
1057  { /* 214 D6 */ "Ö", "&Ouml;", nullptr, nullptr, "Latin capital letter O with diaeresis" },
1058  { /* 215 D7 */ "×", "&times;", nullptr, nullptr, "Multiplication sign" },
1059  { /* 216 D8 */ "Ø", "&Oslash;", nullptr, nullptr, "Latin capital letter O with slash" },
1060  { /* 217 D9 */ "Ù", "&Ugrave;", nullptr, nullptr, "Latin capital letter U with grave" },
1061  { /* 218 DA */ "Ú", "&Uacute;", nullptr, nullptr, "Latin capital letter U with acute" },
1062  { /* 219 DB */ "Û", "&Ucirc;", nullptr, nullptr, "Latin capital letter U with circumflex" },
1063  { /* 220 DC */ "Ü", "&Uuml;", nullptr, nullptr, "Latin capital letter U with diaeresis" },
1064  { /* 221 DD */ "Ý", "&Yacute;", nullptr, nullptr, "Latin capital letter Y with acute" },
1065  { /* 222 DE */ "Þ", "&THORN;", nullptr, nullptr, "Latin capital letter THORN" },
1066  { /* 223 DF */ "ß", "&szlig;", nullptr, nullptr, "Latin small letter sharp s - ess-zed" },
1067  { /* 224 E0 */ "à", "&agrave;", nullptr, nullptr, "Latin small letter a with grave" },
1068  { /* 225 E1 */ "á", "&aacute;", nullptr, nullptr, "Latin small letter a with acute" },
1069  { /* 226 E2 */ "â", "&acirc;", nullptr, nullptr, "Latin small letter a with circumflex" },
1070  { /* 227 E3 */ "ã", "&atilde;", nullptr, nullptr, "Latin small letter a with tilde" },
1071  { /* 228 E4 */ "ä", "&auml;", nullptr, nullptr, "Latin small letter a with diaeresis" },
1072  { /* 229 E5 */ "å", "&aring;", nullptr, nullptr, "Latin small letter a with ring above" },
1073  { /* 230 E6 */ "æ", "&aelig;", nullptr, nullptr, "Latin small letter ae" },
1074  { /* 231 E7 */ "ç", "&ccedil;", nullptr, nullptr, "Latin small letter c with cedilla" },
1075  { /* 232 E8 */ "è", "&egrave;", nullptr, nullptr, "Latin small letter e with grave" },
1076  { /* 233 E9 */ "é", "&eacute;", nullptr, nullptr, "Latin small letter e with acute" },
1077  { /* 234 EA */ "ê", "&ecirc;", nullptr, nullptr, "Latin small letter e with circumflex" },
1078  { /* 235 EB */ "ë", "&euml;", nullptr, nullptr, "Latin small letter e with diaeresis" },
1079  { /* 236 EC */ "ì", "&igrave;", nullptr, nullptr, "Latin small letter i with grave" },
1080  { /* 237 ED */ "í", "&iacute;", nullptr, nullptr, "Latin small letter i with acute" },
1081  { /* 238 EE */ "î", "&icirc;", nullptr, nullptr, "Latin small letter i with circumflex" },
1082  { /* 239 EF */ "ï", "&iuml;", nullptr, nullptr, "Latin small letter i with diaeresis" },
1083  { /* 240 F0 */ "ð", "&eth;", nullptr, nullptr, "Latin small letter eth" },
1084  { /* 241 F1 */ "ñ", "&ntilde;", nullptr, nullptr, "Latin small letter n with tilde" },
1085  { /* 242 F2 */ "ò", "&ograve;", nullptr, nullptr, "Latin small letter o with grave" },
1086  { /* 243 F3 */ "ó", "&oacute;", nullptr, nullptr, "Latin small letter o with acute" },
1087  { /* 244 F4 */ "ô", "&ocirc;", nullptr, nullptr, "Latin small letter o with circumflex" },
1088  { /* 245 F5 */ "õ", "&otilde;", nullptr, nullptr, "Latin small letter o with tilde" },
1089  { /* 246 F6 */ "ö", "&ouml;", nullptr, nullptr, "Latin small letter o with diaeresis" },
1090  { /* 247 F7 */ "÷", "&divide;", nullptr, nullptr, "Division sign" },
1091  { /* 248 F8 */ "ø", "&oslash;", nullptr, nullptr, "Latin small letter o with slash" },
1092  { /* 249 F9 */ "ù", "&ugrave;", nullptr, nullptr, "Latin small letter u with grave" },
1093  { /* 250 FA */ "ú", "&uacute;", nullptr, nullptr, "Latin small letter u with acute" },
1094  { /* 251 FB */ "û", "&ucirc;", nullptr, nullptr, "Latin small letter u with circumflex" },
1095  { /* 252 FC */ "ü", "&uuml;", nullptr, nullptr, "Latin small letter u with diaeresis" },
1096  { /* 253 FD */ "ý", "&yacute;", nullptr, nullptr, "Latin small letter y with acute" },
1097  { /* 254 FE */ "þ", "&thorn;", nullptr, nullptr, "Latin small letter thorn" },
1098  { /* 255 FF */ "ÿ", "&yuml;", nullptr, nullptr, "Latin small letter y with diaeresis" },
1099 
1100 };
1101 
1102 
std::string append(const std::string &s, const std::string &append, const std::string &separator)
Append a string to string.
Definition: Util.cpp:404
std::string ucase(const std::string &value)
Upper Case a string.
Definition: Util.cpp:441
std::string prepend(const std::string &s, int length=0, char pad= '0')
Prepend some number of characters in front of another string.
Definition: Util.cpp:431
int roundUp(float value)
Round a number up.
Definition: Util.cpp:455
int stoi(const std::string &value)
Convert a String to an Integer.
Definition: Util.cpp:295
double stof(const std::string &value)
Convert a String to Float.
Definition: Util.cpp:320
bool feq(double a, double b, double epsilon=0.005f, bool trace=false)
Definition: Util.cpp:710
std::string ftos(double value, int decimals=2)
Convert a Float to String with decimal precision.
Definition: Util.cpp:344
std::string json_number_to_string(const std::string &key, const std::string &data)
Convert a number to a string.
Definition: Util.cpp:17
std::string replace(const std::string &string, const std::string &before, const std::string &after)
Replace a String.
Definition: Util.cpp:480
std::string itos(int value)
Convert an Integer to a String.
Definition: Util.cpp:311
std::vector< std::string > fileList(const std::string &folder)
File Listing.
Definition: Util.cpp:201
std::vector< std::string > findFiles(const std::string &folder, const std::string &match)
Find File.
Definition: Util.cpp:278
bool ends_with(const std::string &value, const std::string &ending)
Check if a string ends with another string.
Definition: Util.cpp:396
std::string makeFileName(const std::string &value)
Make File Name.
Definition: Util.cpp:85
std::string lcase(const std::string &value)
Lower Case a string.
Definition: Util.cpp:448
int system_command(const std::string &cmd, bool show=false)
Execute a system command.
Definition: Util.cpp:153
bool fileExists(const std::string &fileName)
Check if a File or Folder exists.
Definition: Util.cpp:289
int roundDown(float value)
Round a number down.
Definition: Util.cpp:464
float roundCurrency(float value)
Round a number for Currency.
Definition: Util.cpp:469