Subversion Repositories wimsdev

Rev

Rev 8346 | Rev 13932 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2. *********************************************************************************
  3. * J.M. Evers 2/2012                                                             *
  4. * This is all amateur scriblings... So no copyrights.                           *
  5. * This source code file, and compiled objects derived from it,                  *
  6. * can be used and distributed without restriction, including for commercial use *
  7. * No warrenty whatsoever                                                        *
  8. *********************************************************************************
  9.  
  10. general use:
  11. moneyprint number1,number2,number3... DECIMALS
  12. default rounding to 2 decimals (financial math)
  13.  
  14. tot=!exec moneyprint 6.14512 --> 6.15
  15. tot=!exec moneyprint 6.14512 3 --> 6.145
  16. tot=!exec moneyprint 0.1,17,123.4,123.99765 --> 0.10,17.00,123.40,124.00
  17. tot=!exec moneyprint 2*10^7,2E-7 --> 2.00*10^7,2.00*10^-7
  18. !set use_comma
  19. # only for representation ,the outcome can not be used for further arithmetics/calculations
  20. tot=!exec moneyprint 6.14512 --> 6,15
  21. tot=!exec moneyprint 6.14512 3 --> 6,145
  22. tot=!exec moneyprint 0.1,17,123.4,123.99765 --> 0,10 17,00 123,40 124,00
  23. tot=!exec moneyprint 2*10^7,2E-7 --> 2,00*10^7 2,00*10^-7
  24.  
  25. bugs & flaws: no calculations are performed , fractions are not supported
  26.  
  27. CHANGELOG
  28. 2/2012
  29.  modified for general rounding usage; a word 'DECIMALS' can be added to the list of numbers
  30.  tot=!exec moneyprint 2.1,4.123,5  2   // 2 decimals
  31.  tot -> 2.10,4.12,5.00
  32.  tot=!exec moneyprint 2.1,4.123,5  4   // 4 decimals
  33.  tot -> 2.1000,4.1230,5.0000
  34.  tot=!exec moneyprint 2.1,4.123,5
  35.  tot -> 2.10,4.12,5.00 //default value (or old syntax) is 2 decimals  
  36.  
  37. 6/2012
  38.  modified again to support rounding of scientific numbers, like
  39.  tot=!exec moneyprint 1.23456e+06,1.23456*10^6,0.01234e-23 3
  40.  tot -> 1.235e06,1.235e6,0.012e-23
  41.  assumed only powers of 10 [scientific notation]
  42.  
  43. 12/2012
  44.  Modified : using only 10^ in powers
  45.  (e+8 -> *10^8 ; e-8 -> *10^-8)
  46.  Extra syntax error signal (using more than 1 'e')
  47.  
  48. 27/2014
  49.  Modified avoiding truncating of numbers like 15.625 --> 16.62
  50.  
  51. 2/2018
  52.  if variable "w_use_comma" is set (eg in phtml !set use_comma=1), the result is a comma 'decimal' separator:
  53.  moneyprint 1.2345 2 -> 1,23
  54.  moneyprint 1.2345 , 2.34567 , 3.4567 , 5 2 -> 1,23 2,35 3,46 5,00
  55.  (note: in this case (multiple conversions) we use 'spaces' instead of an item ',' list )
  56.  This is INCOMPATIBLE with calculating software : only suitable for REPRESENTATION of (money) numbers
  57.  If env. variable w_use_comma is not set or not "1" , the behaviour is a number with a decimal point
  58.  
  59. */
  60.  
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <string.h>
  64. #include <math.h>
  65. #include <locale.h>
  66.  
  67. #define MAX_DIGITS 128
  68. #define MAX_CONV 32
  69. #define LOCALE "fr_FR.ISO8859-1"
  70.  
  71.  
  72. int main( int argc , char *argv[]){
  73.  if( argc != 2 && argc != 3){
  74.   fprintf(stdout,"error !\nusage:\n!exec moneyprint $your_wims_item_list $precision_word\nexample:\nmoney=!exec moneyprint 1.2,30.1,.4,-.23123456 2\nThe result is a comma separated list: 1.20,30.10,0.40,-0.23\n using 2 decimals\nNote: no calculations are done.\nNo spaces allowed \n");
  75.   exit(0);
  76.  }
  77.  /* test for illegal characters */
  78.  const char *invalid_characters = "\n\"\'!=ABCDFGHIJKLMNOPQRSTUVWYZabcdfghijklmnopqrstuvwyz@#$%&()[]{};:~><?/\\|";
  79.  /* +-*^XxEe are allowed : 12.34e+05  12.34e-08 1x10^5 1.234*10^123*/
  80.  char *input;
  81.  input = argv[1];
  82.  while (*input){
  83.   if ( strchr(invalid_characters, *input) ){
  84.    fprintf(stdout,"error !\nfound illegal character \"%c\" in argument\n",*input);
  85.    exit(0);
  86.   }
  87.   input++;
  88.  }
  89.  int DECIMALS;
  90.  if(argv[2] != NULL){
  91.   DECIMALS = atoi(argv[2]);
  92.   if(DECIMALS > MAX_DIGITS){
  93.    fprintf(stdout,"error ! maximum amount of decimals is %d \n",MAX_DIGITS);exit(0);
  94.   }
  95.  }
  96.  else
  97.  {
  98.   DECIMALS = 2;
  99.  }
  100.  char *sep = ",";
  101.  char *ptr;
  102.  char word[MAX_DIGITS];
  103.  char exponent[MAX_DIGITS];
  104.  char number[MAX_DIGITS];
  105.  char *w_use_comma = getenv("w_use_comma");
  106.  if( w_use_comma == NULL ){ w_use_comma = "0";}
  107.  int cnt = 1;int powE = 0;int idx1 = 0;int idx2 = 0;int length = 0;int i = 0;int pow10 = 0;
  108.  double correction = 1/(pow(10,DECIMALS+6)); /* a reasonable guess...to avoid truncating 15.625 --> 16.63 */
  109.  double ascii_number;
  110.  input = argv[1];
  111.  ptr = strtok(input,",");
  112.  while( ptr != NULL){
  113.   if(  cnt > MAX_CONV ){fprintf(stdout,"ERROR too many (> %d)conversion \n",MAX_CONV);exit(0);}
  114.   /* next item in input argv[1] */
  115.   strncpy( word, ptr, MAX_DIGITS);
  116.   length = strlen(ptr);
  117.   if(length > MAX_DIGITS-1){fprintf(stdout,"ERROR string too large\n");exit(0);}
  118.   /* reset counters */
  119.   powE = 0;pow10 = 0;idx1 = 0;idx2 = 0;i = 0;
  120.   for( i = 0; i < length ; i++){
  121.    if(powE > 1 ){ fprintf(stdout,"ERROR in syntax\n");exit(0);}
  122.    if( idx1 + idx2  >  MAX_DIGITS-1){ fprintf(stdout,"ERROR string too large\n");exit(0);}
  123.    switch( word[i] ){
  124.     case '+' : break; /* do not use 10^+2 */
  125.     case 'e' : powE++;break;
  126.     case 'E' : powE++;break;
  127.     case 'x' : pow10++;break;
  128.     case '*' : pow10++;break;
  129.     /* word[2] = '^' --> 10^5 => 1.00*10^5 */
  130.     case '^' : if( i != 2 ){ pow10 = 5; }else{ idx1 = 1;idx2 = 0;pow10 = 4;} break;
  131.     default  : if( pow10 > 0 ){
  132.                 pow10++;
  133.                 if( pow10 > 4 ){ /*  *10^ = 4 chars */
  134.                  exponent[idx2] = word[i];
  135.                  idx2++;
  136.                 }
  137.                }
  138.                else
  139.                {
  140.                 if(powE > 0){
  141.                  exponent[idx2] = word[i];
  142.                  idx2++;
  143.                 }
  144.                 else
  145.                 {
  146.                  number[idx1] = word[i];
  147.                  idx1++;
  148.                 }
  149.                }
  150.                break;
  151.    }
  152.   }
  153.   exponent[idx2] = '\0';
  154.   number[idx1] = '\0';
  155.   /* atof needs decimal point locale, like "C" */
  156.   setlocale(LC_NUMERIC, "C");
  157.   ascii_number = atof(number);
  158.   if( ascii_number > 0 ){ ascii_number = ascii_number + correction;}else{ ascii_number = ascii_number - correction; }
  159.   if ( strcmp( w_use_comma , "1") == 0 ){ setlocale(LC_NUMERIC, LOCALE);sep = " "; }
  160.   if( powE == 1 || pow10> 0 ){
  161.    if(cnt > 1){
  162.     fprintf( stdout , "%s%.*f*10^%s" ,sep, DECIMALS , ascii_number , exponent );
  163.    }
  164.    else
  165.    {
  166.     fprintf( stdout , "%.*f*10^%s" , DECIMALS , ascii_number , exponent );
  167.    }
  168.   }
  169.   else
  170.   {
  171.    if(cnt > 1 ){
  172.     fprintf( stdout , "%s%.*f" ,sep, DECIMALS , ascii_number); 
  173.    }
  174.    else
  175.    {
  176.     fprintf( stdout , "%.*f" , DECIMALS , ascii_number);       
  177.    }
  178.   }
  179.   cnt++;
  180.   ptr = strtok(NULL,",");
  181.  }
  182.  fprintf(stdout,"\n");
  183.  return 0;
  184. }
  185.