bcalc

cli bitcoin unit calculator
git clone git://jb55.com/bcalc
Log | Files | Refs | README | LICENSE

commit 32134b635f98b971c520ec5d9396bd74977c2ffa
parent a5e45a2b7e84f6f3076f3a021fd2adbb137c44d9
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 16 Dec 2017 22:37:34 -0800

working nicely

Diffstat:
MMakefile | 9+++++----
Abcalc.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mnum.c | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mnum.h | 15+++++++++------
Mparser.y | 28++++------------------------
5 files changed, 170 insertions(+), 51 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,9 +3,10 @@ BIN=bcalc DEPS=$(wildcard deps/*/*.c) $(GEN) PREFIX ?= /usr/local -DEPS = $(wildcard deps/*/*.c) +SRC = num.c +DEPS = $(wildcard deps/*/*.c) $(SRC) OBJS = $(DEPS:.c=.o) parser.tab.o lex.yy.o -GEN=parser.tab.c parser.tab.h lex.yy.c $(OBJS) +GEN = parser.tab.c parser.tab.h lex.yy.c $(OBJS) all: $(BIN) @@ -20,8 +21,8 @@ install: $(BIN) mkdir -p $(PREFIX)/bin cp $(BIN) $(PREFIX)/bin -$(BIN): $(OBJS) - $(CC) -o $@ num.c $(OBJS) +$(BIN): $(OBJS) bcalc.c + $(CC) -Ideps -o $@ bcalc.c $(OBJS) clean: rm -f $(GEN) diff --git a/bcalc.c b/bcalc.c @@ -0,0 +1,76 @@ + +#include <stdlib.h> +#include <stdio.h> +#include "commander/commander.h" +#include "num.h" + +extern int yylex(); +extern int yyparse(); +extern enum unit g_output_format; + +void yyerror(const char* s); + +struct settings { + enum unit format; + int print_unit; +}; + +#define format_setting(name, unit) static void name(command_t *self) { \ + ((struct settings*)self->data)->format = unit; \ +} + +static void print_unit(command_t *self) { \ + ((struct settings*)self->data)->print_unit = 1; \ +} + + +format_setting(btc, UNIT_BTC) +format_setting(mbtc, UNIT_MBTC) +format_setting(bits, UNIT_BITS) +format_setting(finney, UNIT_FINNEY) +format_setting(satoshis, UNIT_SATOSHI) +format_setting(msatoshis, UNIT_MSATOSHI) + + + +int main(int argc, char *argv[argc]) { + command_t cmd; + struct settings settings = { .print_unit = 0, .format = UNIT_SATOSHI }; + cmd.data = (void*)&settings; + + command_init(&cmd, argv[0], "0.0.1"); + + command_option(&cmd, "-B", "--btc", "output BTC", btc); + command_option(&cmd, "-M", "--mbtc", "output mBTC", mbtc); + command_option(&cmd, "-b", "--bits", "output bits", bits); + command_option(&cmd, "-f", "--finneys", "output finneys", finney); + command_option(&cmd, "-s", "--satoshis", "output satoshis (default)", satoshis); + command_option(&cmd, "-m", "--millisatoshis", "output millisatoshis", msatoshis); + command_option(&cmd, "-p", "--print-unit", "output the selected unit at the end", + print_unit); + + command_parse(&cmd, argc, argv); + /* printf("additional args:\n"); */ + /* for (int i = 0; i < cmd.argc; ++i) { */ + /* printf(" - '%s'\n", cmd.argv[i]); */ + /* } */ + command_free(&cmd); + + g_output_format = settings.format; + + do { + yyparse(); + } while(!feof(stdin)); + + if (settings.print_unit) + printf(" %s\n", unit_name(settings.format)); + else + putchar('\n'); + + return 0; +} + +void yyerror(const char* s) { + fprintf(stderr, "Parse error: %s\n", s); + exit(1); +} diff --git a/num.c b/num.c @@ -3,6 +3,7 @@ #include <assert.h> #include <math.h> #include <inttypes.h> +#include <string.h> #include "num.h" void @@ -21,15 +22,15 @@ num_to_msat(struct num *num) { assert("fractional millisatoshis are not yet supported"); return (int64_t)val; case UNIT_SATOSHI: - return (int64_t)(val * 1000); + return (int64_t)(val * SATOSHI); case UNIT_FINNEY: - return (int64_t)(val * 10000); + return (int64_t)(val * FINNEY); case UNIT_BITS: - return (int64_t)(val * 100000); + return (int64_t)(val * BITS); case UNIT_MBTC: - return (int64_t)(val * 100000000); + return (int64_t)(val * MBTC); case UNIT_BTC: - return (int64_t)(val * 100000000000); + return (int64_t)(val * BTC); } } @@ -38,15 +39,15 @@ num_to_msat(struct num *num) { case UNIT_MSATOSHI: return val; case UNIT_SATOSHI: - return val * 1000; + return val * SATOSHI; case UNIT_FINNEY: - return val * 10000; + return val * FINNEY; case UNIT_BITS: - return val * 100000; + return val * BITS; case UNIT_MBTC: - return val * 100000000; + return val * MBTC; case UNIT_BTC: - return val * 100000000000; + return val * BTC; } } @@ -79,8 +80,6 @@ num_div(struct num *dst, struct num *a, struct num *b) { dst->type = TYPE_INT; dst->unit = UNIT_MSATOSHI; dst->intval = num_to_msat(a) / num_to_msat(b); - assert(fabs((double)dst->intval - - ((double)num_to_msat(a) / (double)num_to_msat(b))) <= 0.00005); } void @@ -92,10 +91,70 @@ num_assign(struct num *dst, struct num *a) { *dst = num; } +int64_t +unit_msat_multiple(enum unit format) { + switch (format) { + case UNIT_MSATOSHI: return MSATOSHI; + case UNIT_SATOSHI: return SATOSHI; + case UNIT_FINNEY: return FINNEY; + case UNIT_BITS: return BITS; + case UNIT_MBTC: return MBTC; + case UNIT_BTC: return BTC; + } +} + + +static void +trim_zeros (char *s, int n) +{ + char *p; + int count; + + p = strchr (s,'.'); // Find decimal point, if any. + if (p != NULL) { + count = n; // Adjust for more or less decimals. + while (count >= 0) { // Maximum decimals allowed. + count--; + if (*p == '\0') // If there's less than desired. + break; + p++; // Next character. + } + + *p-- = '\0'; // Truncate string. + while (*p == '0') // Remove trailing zeros. + *p-- = '\0'; + + if (*p == '.') { // If all decimals were zeros, remove ".". + *p = '\0'; + } + } +} + void -num_print(struct num *num) { - if (num->type == TYPE_FLOAT) - printf("%f ", num->floatval); - else - printf("%" PRId64, num->intval); +num_print(struct num *num, enum unit format) { + static char buffer[255]; + int64_t msat_multiple = unit_msat_multiple(format); + + if (format) { + } + + double d = num->type == TYPE_FLOAT? num->floatval : (double)num->intval; + d /= (double)msat_multiple; + sprintf (buffer, "%.11f", d); + trim_zeros(buffer, 1); + printf("%s", buffer); +} + + + +char * +unit_name(enum unit unit) { + switch (unit) { + case UNIT_MSATOSHI: return "msat"; + case UNIT_SATOSHI: return "sat"; + case UNIT_FINNEY: return "finney"; + case UNIT_BITS: return "bits"; + case UNIT_MBTC: return "mBTC"; + case UNIT_BTC: return "BTC"; + } } diff --git a/num.h b/num.h @@ -4,11 +4,13 @@ #include <stdint.h> -#define MSATOSHI 100000000000LL -#define SATOSHI 100000000LL -#define FINNEY 10000000LL -#define BITS 1000000LL -#define MBTC 1000LL +// multiples of msat +#define MSATOSHI 1LL +#define SATOSHI 1000LL +#define FINNEY 10000LL +#define BITS 100000LL +#define MBTC 100000000LL +#define BTC 100000000000LL enum unit { UNIT_BTC, @@ -42,6 +44,7 @@ void num_mul(struct num *dst, struct num *a, struct num *b); void num_div(struct num *dst, struct num *a, struct num *b); void num_assign(struct num *dst, struct num *a); void num_init(struct num *num); -void num_print(struct num *num); +void num_print(struct num *num, enum unit unit); +char *unit_name(enum unit unit); #endif /* UNIT_H */ diff --git a/parser.y b/parser.y @@ -5,13 +5,8 @@ #include "num.h" -extern int yylex(); -extern int yyparse(); -extern FILE* yyin; +enum unit g_output_format; -char buffer[255]; - -void yyerror(const char* s); %} %union { @@ -41,11 +36,10 @@ calc: ; line: T_NEWLINE - | expr T_NEWLINE { num_print(&$1); printf("\n"); } -; + | expr T_NEWLINE { num_print(&$1, g_output_format); } + ; -expr: - | T_INT T_UNIT { num_init(&$$); +expr: T_INT T_UNIT { num_init(&$$); $$.intval = $1; $$.type = TYPE_INT; $$.unit = $2; @@ -74,17 +68,3 @@ expr: %% -int main() { - yyin = stdin; - - do { - yyparse(); - } while(!feof(yyin)); - - return 0; -} - -void yyerror(const char* s) { - fprintf(stderr, "Parse error: %s\n", s); - exit(1); -}