1,30 → 1,16 |
/* |
********************************************************************************* |
* J.M. Evers 2/2012 * |
* J.M. Evers 3/2012 * |
* This is all amateur scriblings... So no copyrights. * |
* This source code file, and compiled objects derived from it, * |
* can be used and distributed without restriction, including for commercial use * |
* No warrenty whatsoever * |
********************************************************************************* |
general use: |
rounding to 2 decimals (financial math) |
tot=!exec moneyprint 0.1,17,123.4,123.99765 |
tot -> 0.10,17.00,123.40,124.00 |
|
general use: |
moneyprint number1,number2,number3... DECIMALS |
default rounding to 2 decimals (financial math) |
|
tot=!exec moneyprint 6.14512 --> 6.15 |
tot=!exec moneyprint 6.14512 3 --> 6.145 |
tot=!exec moneyprint 0.1,17,123.4,123.99765 --> 0.10,17.00,123.40,124.00 |
tot=!exec moneyprint 2*10^7,2E-7 --> 2.00*10^7,2.00*10^-7 |
!set use_comma |
# only for representation ,the outcome can not be used for further arithmetics/calculations |
tot=!exec moneyprint 6.14512 --> 6,15 |
tot=!exec moneyprint 6.14512 3 --> 6,145 |
tot=!exec moneyprint 0.1,17,123.4,123.99765 --> 0,10 17,00 123,40 124,00 |
tot=!exec moneyprint 2*10^7,2E-7 --> 2,00*10^7 2,00*10^-7 |
|
bugs & flaws: no calculations are performed , fractions are not supported |
|
CHANGELOG |
2/2012 |
modified for general rounding usage; a word 'DECIMALS' can be added to the list of numbers |
tot=!exec moneyprint 2.1,4.123,5 2 // 2 decimals |
34,29 → 20,21 |
tot=!exec moneyprint 2.1,4.123,5 |
tot -> 2.10,4.12,5.00 //default value (or old syntax) is 2 decimals |
|
6/2012 |
6/2012. |
modified again to support rounding of scientific numbers, like |
tot=!exec moneyprint 1.23456e+06,1.23456*10^6,0.01234e-23 3 |
tot -> 1.235e06,1.235e6,0.012e-23 |
|
assumed only powers of 10 [scientific notation] |
|
12/2012 |
Modified : using only 10^ in powers |
(e+8 -> *10^8 ; e-8 -> *10^-8) |
Extra syntax error signal (using more than 1 'e') |
Modified : using only 10^ in powers |
(e+8 -> *10^8 ; e-8 -> *10^-8) |
Extra syntax error signal (using more than 1 'e') |
|
27/2014 |
Modified avoiding truncating of numbers like 15.625 --> 16.62 |
Modified avoiding truncating of numbers like 15.625 --> 16.62 |
|
2/2018 |
if variable "w_use_comma" is set (eg in phtml !set use_comma=1), the result is a comma 'decimal' separator: |
moneyprint 1.2345 2 -> 1,23 |
moneyprint 1.2345 , 2.34567 , 3.4567 , 5 2 -> 1,23 2,35 3,46 5,00 |
(note: in this case (multiple conversions) we use 'spaces' instead of an item ',' list ) |
This is INCOMPATIBLE with calculating software : only suitable for REPRESENTATION of (money) numbers |
If env. variable w_use_comma is not set or not "1" , the behaviour is a number with a decimal point |
|
5/2019 use "strlcpy, strlcat" - size-bounded string copying and concatenation |
*/ |
|
#include <stdio.h> |
63,123 → 41,142 |
#include <stdlib.h> |
#include <string.h> |
#include <math.h> |
#include <locale.h> |
|
#define MAX_DIGITS 128 |
#define MAX_DIGITS 32 |
#define MAX_CONV 32 |
#define LOCALE "fr_FR.ISO8859-1" |
|
|
int main( int argc , char *argv[]){ |
if( argc != 2 && argc != 3){ |
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"); |
exit(0); |
} |
/* test for illegal characters */ |
const char *invalid_characters = "\n\"\'!=ABCDFGHIJKLMNOPQRSTUVWYZabcdfghijklmnopqrstuvwyz@#$%&()[]{};:~><?/\\|"; |
/* +-*^XxEe are allowed : 12.34e+05 12.34e-08 1x10^5 1.234*10^123*/ |
char *input; |
input = argv[1]; |
while (*input){ |
if ( strchr(invalid_characters, *input) ){ |
fprintf(stdout,"error !\nfound illegal character \"%c\" in argument\n",*input); |
exit(0); |
} |
input++; |
} |
int DECIMALS; |
if(argv[2] != NULL){ |
DECIMALS = atoi(argv[2]); |
if(DECIMALS > MAX_DIGITS){ |
fprintf(stdout,"error ! maximum amount of decimals is %d \n",MAX_DIGITS);exit(0); |
} |
} |
else |
{ |
DECIMALS = 2; |
} |
char *sep = ","; |
char *ptr; |
char word[MAX_DIGITS]; |
char exponent[MAX_DIGITS]; |
char number[MAX_DIGITS]; |
char *w_use_comma = getenv("w_use_comma"); |
if( w_use_comma == NULL ){ w_use_comma = "0";} |
int cnt = 1;int powE = 0;int idx1 = 0;int idx2 = 0;int length = 0;int i = 0;int pow10 = 0; |
double correction = 1/(pow(10,DECIMALS+6)); /* a reasonable guess...to avoid truncating 15.625 --> 16.63 */ |
double ascii_number; |
input = argv[1]; |
ptr = strtok(input,","); |
while( ptr != NULL){ |
if( cnt > MAX_CONV ){fprintf(stdout,"ERROR too many (> %d)conversion \n",MAX_CONV);exit(0);} |
/* next item in input argv[1] */ |
strlcpy( word, ptr, sizeof(word)); |
length = strlen(ptr); |
if(length > MAX_DIGITS-1){fprintf(stdout,"ERROR string too large\n");exit(0);} |
/* reset counters */ |
powE = 0;pow10 = 0;idx1 = 0;idx2 = 0;i = 0; |
for( i = 0; i < length ; i++){ |
if(powE > 1 ){ fprintf(stdout,"ERROR in syntax\n");exit(0);} |
if( idx1 + idx2 > MAX_DIGITS-1){ fprintf(stdout,"ERROR string too large\n");exit(0);} |
switch( word[i] ){ |
case '+' : break; /* do not use 10^+2 */ |
case 'e' : powE++;break; |
case 'E' : powE++;break; |
case 'x' : pow10++;break; |
case '*' : pow10++;break; |
/* word[2] = '^' --> 10^5 => 1.00*10^5 */ |
case '^' : if( i != 2 ){ pow10 = 5; }else{ idx1 = 1;idx2 = 0;pow10 = 4;} break; |
default : if( pow10 > 0 ){ |
pow10++; |
if( pow10 > 4 ){ /* *10^ = 4 chars */ |
exponent[idx2] = word[i]; |
idx2++; |
if( argc != 2 && argc != 3){ |
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"); |
exit(0); |
} |
/* test for illegal characters */ |
const char *invalid_characters = "\n\"\'!=ABCDFGHIJKLMNOPQRSTUVWYZabcdfghijklmnopqrstuvwyz@#$%&()[]{};:~><?/\\|"; |
/* +-*^XxEe are allowed : 12.34e+05 12.34e-08 1x10^5 1.234*10^123*/ |
char *input; |
input = argv[1]; |
while (*input){ |
if ( strchr(invalid_characters, *input) ){ |
fprintf(stdout,"error !\nfound illegal character \"%c\" in argument\n",*input); |
exit(0); |
} |
input++; |
} |
int DECIMALS; |
if(argv[2] != NULL){ |
DECIMALS = atoi(argv[2]); |
if(DECIMALS > MAX_DIGITS){ |
fprintf(stdout,"error ! maximum amount of decimals is %d \n",MAX_DIGITS);exit(0); |
} |
} |
else |
{ |
DECIMALS = 2; |
} |
char *ptr; |
char word[MAX_DIGITS]; |
char exponent[MAX_DIGITS]; |
char number[MAX_DIGITS]; |
int cnt = 1; |
int powE = 0; |
int idx1 = 0; |
int idx2 = 0; |
int length= 0; |
int i = 0; |
int pow10 = 0; |
double correction = 1/(pow(10,DECIMALS+6)); /* a reasonable guess...to avoid truncating 15.625 --> 16.63 */ |
double ascii_number; |
input = argv[1]; |
ptr = strtok(input,","); |
while( ptr != NULL){ |
if( cnt > MAX_CONV ){ |
fprintf(stdout,"ERROR too many (> %d)conversion \n",MAX_CONV); |
exit(0); |
} |
// next item in input argv[1] |
strncpy( word, ptr, MAX_DIGITS); |
length = strlen(ptr); |
if(length > MAX_DIGITS-1){ |
fprintf(stdout,"ERROR string too large\n"); |
exit(0); |
} |
//reset counters |
powE = 0; |
pow10 = 0; |
idx1 = 0; |
idx2 = 0; |
i = 0; |
for( i = 0; i < length ; i++){ |
if(powE > 1 ){ |
fprintf(stdout,"ERROR in syntax\n"); |
exit(0); |
} |
if( idx1 + idx2 > MAX_DIGITS-1){ |
fprintf(stdout,"ERROR string too large\n"); |
exit(0); |
} |
switch( word[i] ){ |
case '+' : break; /* do not use 10^+2 */ |
case 'e' : powE++;break; |
case 'E' : powE++;break; |
case 'x' : pow10++;break; |
case '*' : pow10++;break; |
case '^' : pow10=5;break; |
default : |
if( pow10 > 0 ){ |
pow10++; |
if( pow10 > 4 ){ /* *10^ = 4 chars */ |
exponent[idx2] = word[i]; |
idx2++; |
} |
} |
} |
else |
{ |
if(powE > 0){ |
exponent[idx2] = word[i]; |
idx2++; |
} |
else |
{ |
number[idx1] = word[i]; |
idx1++; |
{ |
if(powE > 0){ |
exponent[idx2] = word[i]; |
idx2++; |
} |
else |
{ |
number[idx1] = word[i]; |
idx1++; |
} |
} |
} |
break; |
} |
} |
exponent[idx2] = '\0'; |
number[idx1] = '\0'; |
/* atof needs decimal point locale, like "C" */ |
setlocale(LC_NUMERIC, "C"); |
ascii_number = atof(number); |
if( ascii_number > 0 ){ ascii_number = ascii_number + correction;}else{ ascii_number = ascii_number - correction; } |
if ( strcmp( w_use_comma , "1") == 0 ){ setlocale(LC_NUMERIC, LOCALE);sep = " "; } |
if( powE == 1 || pow10> 0 ){ |
if(cnt > 1){ |
fprintf( stdout , "%s%.*f*10^%s" ,sep, DECIMALS , ascii_number , exponent ); |
} |
else |
{ |
fprintf( stdout , "%.*f*10^%s" , DECIMALS , ascii_number , exponent ); |
} |
} |
else |
{ |
if(cnt > 1 ){ |
fprintf( stdout , "%s%.*f" ,sep, DECIMALS , ascii_number); |
} |
else |
{ |
fprintf( stdout , "%.*f" , DECIMALS , ascii_number); |
} |
} |
cnt++; |
ptr = strtok(NULL,","); |
} |
fprintf(stdout,"\n"); |
return 0; |
break; |
} |
} |
exponent[idx2] = '\0'; |
number[idx1] = '\0'; |
ascii_number = atof(number); |
if( ascii_number > 0 ){ |
ascii_number = ascii_number + correction; |
} |
else |
{ |
ascii_number = ascii_number - correction; |
} |
if( powE == 1 || pow10> 0 ){ |
if(cnt > 1){ |
fprintf( stdout , ",%.*f*10^%s" , DECIMALS , ascii_number , exponent ); |
} |
else |
{ |
fprintf( stdout , "%.*f*10^%s" , DECIMALS , ascii_number , exponent ); |
} |
} |
else |
{ |
if(cnt > 1 ){ |
fprintf( stdout , ",%.*f" , DECIMALS , ascii_number); |
} |
else |
{ |
fprintf( stdout , "%.*f" , DECIMALS , ascii_number); |
} |
} |
cnt++; |
ptr = strtok(NULL,","); |
} |
fprintf(stdout,"\n"); |
return 0; |
} |
|