diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e722098..84344f9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ include(sources.cmake) # Options #----------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build shared library and only the shared library if \"ON\", default is static" OFF) +option(WITH_MP_FPRINTF "Build and link the rather large mp_fprintf if \"ON\"" OFF) #----------------------------------------------------------------------------- # Compose CFLAGS @@ -181,6 +182,10 @@ if(BUILD_SHARED_LIBS) ) endif() +if(WITH_MP_FPRINTF) + # Only the big-integers get their own treatment, the rest gets send to fprintf + set(LTM_C_FLAGS -DMP_WITH_MP_FPRINTF -Wno-switch-enum -Wno-format-nonliteral -Wno-format ) +endif() # generate package version file write_basic_package_version_file( ${PROJECT_VERSION_FILE} diff --git a/appveyor.yml b/appveyor.yml index 2134f2dd..d3f987e2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,8 +13,8 @@ image: - Visual Studio 2015 environment: matrix: - - CFLAGS_VAR: "" - CFLAGS_VAR_DLL: "CFLAGS=\"/Ox /MD /DLTM_TEST_DYNAMIC\"" + - CFLAGS_VAR: "CFLAGS=\"/Ox /DMP_WITH_MP_FPRINTF /wd4061 /wd4774\"" + CFLAGS_VAR_DLL: "CFLAGS=\"/Ox /MD /DLTM_TEST_DYNAMIC /DMP_WITH_MP_FPRINTF /wd4061 /wd4774\"" build_script: - cmd: >- if "Visual Studio 2022"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" @@ -27,4 +27,4 @@ build_script: nmake -f makefile.msvc test_dll.exe %CFLAGS_VAR_DLL% test_script: - cmd: test.exe -- cmd: test_dll.exe +- cmd: test_dll.exe diff --git a/demo/test.c b/demo/test.c index 2fa6e08d..cdf8b3f2 100644 --- a/demo/test.c +++ b/demo/test.c @@ -325,7 +325,47 @@ static int test_mp_fread_fwrite(void) mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } +#ifdef MP_WITH_MP_FPRINTF +static int test_mp_fprintf(void) +{ + mp_int a, b; + FILE *tmp = NULL; + int written; + size_t read; + char buf_fprintf[1024] = {0}; + const char *expected_output = + "signed -123 unsigned 456 double 3.141593 bigint-16 >0x17B8F8FB141F0A4000000000000000000000000001Uu+FiK7mf00000<" + "bigint-2 0b1100000111000100111010000101111001110010000100011111101110100011010110010110100110101010110110001" + "Float: +0.6931471806 Percent: % Log: some logfi"; + + DOR(mp_init_multi(&a, &b, NULL)); + + mp_set_ul(&a, 123456uL); + mp_set_ul(&b, 654321uL); + DO(mp_expt_n(&a, 5, &a)); + DO(mp_expt_n(&b, 5, &b)); + tmp = tmpfile(); + written = mp_fprintf(tmp, + "signed %d unsigned %u double %f bigint-16 >%-#Zx%0*ZK<" + "bigint-2 %#ZbFloat: %+.10Lf Percent: %% Log: %.10s", + -123, 456, 3.14159265, &a, &a, 35, &b, + 0.69314718055994530941723212145817656807L, "some logfile entry blabla"); + + rewind(tmp); + + read = fread(buf_fprintf, 1, sizeof(buf_fprintf), tmp); + EXPECT(written == (int)read); + EXPECT(strcmp(buf_fprintf, expected_output) == 0); + fclose(tmp); + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + if (tmp != NULL) fclose(tmp); + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} +#endif static mp_err very_random_source(void *out, size_t size) { memset(out, 0xff, size); @@ -2567,6 +2607,9 @@ static int unit_tests(int argc, char **argv) T1(mp_dr_reduce, MP_DR_REDUCE), T2(mp_pack_unpack,MP_PACK, MP_UNPACK), T2(mp_fread_fwrite, MP_FREAD, MP_FWRITE), +#ifdef MP_WITH_MP_FPRINTF + T1(mp_fprintf, MP_FPRINTF), +#endif T1(mp_get_u32, MP_GET_I32), T1(mp_get_u64, MP_GET_I64), T1(mp_get_ul, MP_GET_L), diff --git a/doc/bn.tex b/doc/bn.tex index 63e71633..b8587646 100644 --- a/doc/bn.tex +++ b/doc/bn.tex @@ -2466,6 +2466,17 @@ \subsection{To ASCII} mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream); \end{alltt} + +If \texttt{MP\_WITH\_MP\_FPRINTF} is defined a function \texttt{mp\_fprintf} is made available +that behaves like \texttt{fprintf(3)}. The modifier for the bigint is \texttt{Z}. there is also +the specifier \texttt{K} to print bigints with radix 64. +\index{mp\_fprintf} +\begin{alltt} +int mp_fprintf(FILE *stream, const char *s, ...) +\end{alltt} +Some of the options from C23 (ISO/IEC 9899:2024) are not implemented, the compiler support +is too sparse for now. + \subsection{From ASCII} \index{mp\_read\_radix} \begin{alltt} diff --git a/doc/tommath.3 b/doc/tommath.3 index fabaaf5d..03b5dd42 100644 --- a/doc/tommath.3 +++ b/doc/tommath.3 @@ -226,6 +226,24 @@ Computes the extended Euclidean algorithm: \fBa * U1 + b * U2 = U3\fP Set the argument for \fBU1, U2, U3\fP to \fBNULL\fP to ignore the respective output. .in -1i +.LP +.BI "int mp_fprintf(FILE * " stream ", const char * " format ", " ... " )" +.in 1i +Behaves like \fBfprintf(3)\fP. The modifier for a bigint is \fBZ\fP. There is also the specifier +\fBK\fP to print mp_ints in radix 64. +.br +Example: +.in +4n +.EX + mp_fprintf(stdout,"The result number %d is %Zd\\n", result_idx, &bigint); +.EE +.in -4n +.br +Returns the number of characters written or a negative value in case of an error. +.br +Some of the options from C23 (ISO/IEC 9899:2024) are not implemented. +.in -1i + .LP .BI "mp_err mp_fread(mp_int *" a ", int " radix ", FILE *" stream ")" .in 1i diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj index 080b7e0d..595479e1 100644 --- a/libtommath_VS2008.vcproj +++ b/libtommath_VS2008.vcproj @@ -428,6 +428,10 @@ RelativePath="mp_exteuclid.c" > + + @@ -844,6 +848,10 @@ RelativePath="s_mp_fp_log_d.c" > + + @@ -892,6 +900,10 @@ RelativePath="s_mp_mul_toom.c" > + + @@ -916,6 +928,10 @@ RelativePath="s_mp_rand_source.c" > + + diff --git a/makefile b/makefile index 6daa522b..3011cd0f 100644 --- a/makefile +++ b/makefile @@ -29,28 +29,29 @@ LCOV_ARGS=--directory . OBJECTS=mp_2expt.o mp_abs.o mp_add.o mp_add_d.o mp_addmod.o mp_and.o mp_clamp.o mp_clear.o mp_clear_multi.o \ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count_bits.o mp_cutoffs.o \ mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \ -mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \ -mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \ -mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \ -mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \ -mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \ -mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \ -mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ -mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ -mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o \ -mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o \ -mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o \ -mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o mp_sqrmod.o mp_sqrt.o \ -mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o \ -mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o s_mp_div_3.o \ -s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_fp_log.o \ -s_mp_fp_log_d.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log_2expt.o \ -s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o s_mp_mul_high.o \ -s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o s_mp_prime_tab.o \ -s_mp_radix_map.o s_mp_radix_size_overestimate.o s_mp_rand_platform.o s_mp_rand_source.o s_mp_sqr.o \ -s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o \ -s_mp_warray_put.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fprintf.o mp_fread.o \ +mp_from_sbin.o mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o \ +mp_get_mag_u32.o mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o \ +mp_init_i32.o mp_init_i64.o mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o \ +mp_init_u64.o mp_init_ul.o mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o \ +mp_mod.o mp_mod_2d.o mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o \ +mp_mul.o mp_mul_2.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o \ +mp_prime_fermat.o mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o \ +mp_prime_next_prime.o mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o \ +mp_radix_size.o mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o \ +mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \ +mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \ +mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o \ +mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \ +mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o \ +s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o \ +s_mp_fp_log.o s_mp_fp_log_d.o s_mp_fprint.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o \ +s_mp_log_2expt.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ +s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_parse_printf_token.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_platform.o s_mp_rand_source.o s_mp_sprint.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o \ +s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o s_mp_warray_put.o s_mp_zero_buf.o \ +s_mp_zero_digs.o #END_INS diff --git a/makefile.mingw b/makefile.mingw index 10f2bd59..7b4c2c8d 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -31,28 +31,29 @@ LIBMAIN_D =libtommath.dll OBJECTS=mp_2expt.o mp_abs.o mp_add.o mp_add_d.o mp_addmod.o mp_and.o mp_clamp.o mp_clear.o mp_clear_multi.o \ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count_bits.o mp_cutoffs.o \ mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \ -mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \ -mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \ -mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \ -mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \ -mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \ -mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \ -mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ -mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ -mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o \ -mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o \ -mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o \ -mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o mp_sqrmod.o mp_sqrt.o \ -mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o \ -mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o s_mp_div_3.o \ -s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_fp_log.o \ -s_mp_fp_log_d.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log_2expt.o \ -s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o s_mp_mul_high.o \ -s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o s_mp_prime_tab.o \ -s_mp_radix_map.o s_mp_radix_size_overestimate.o s_mp_rand_platform.o s_mp_rand_source.o s_mp_sqr.o \ -s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o \ -s_mp_warray_put.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fprintf.o mp_fread.o \ +mp_from_sbin.o mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o \ +mp_get_mag_u32.o mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o \ +mp_init_i32.o mp_init_i64.o mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o \ +mp_init_u64.o mp_init_ul.o mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o \ +mp_mod.o mp_mod_2d.o mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o \ +mp_mul.o mp_mul_2.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o \ +mp_prime_fermat.o mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o \ +mp_prime_next_prime.o mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o \ +mp_radix_size.o mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o \ +mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \ +mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \ +mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o \ +mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \ +mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o \ +s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o \ +s_mp_fp_log.o s_mp_fp_log_d.o s_mp_fprint.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o \ +s_mp_log_2expt.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ +s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_parse_printf_token.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_platform.o s_mp_rand_source.o s_mp_sprint.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o \ +s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o s_mp_warray_put.o s_mp_zero_buf.o \ +s_mp_zero_digs.o HEADERS_PUB=tommath.h HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB) diff --git a/makefile.msvc b/makefile.msvc index f160f2cc..60a85dbd 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -27,28 +27,29 @@ LIBMAIN_D = tommath.dll OBJECTS=mp_2expt.obj mp_abs.obj mp_add.obj mp_add_d.obj mp_addmod.obj mp_and.obj mp_clamp.obj mp_clear.obj mp_clear_multi.obj \ mp_cmp.obj mp_cmp_d.obj mp_cmp_mag.obj mp_cnt_lsb.obj mp_complement.obj mp_copy.obj mp_count_bits.obj mp_cutoffs.obj \ mp_div.obj mp_div_2.obj mp_div_2d.obj mp_div_d.obj mp_dr_is_modulus.obj mp_dr_reduce.obj mp_dr_setup.obj \ -mp_error_to_string.obj mp_exch.obj mp_expt_n.obj mp_exptmod.obj mp_exteuclid.obj mp_fread.obj mp_from_sbin.obj \ -mp_from_ubin.obj mp_fwrite.obj mp_gcd.obj mp_get_double.obj mp_get_i32.obj mp_get_i64.obj mp_get_l.obj mp_get_mag_u32.obj \ -mp_get_mag_u64.obj mp_get_mag_ul.obj mp_grow.obj mp_hash.obj mp_init.obj mp_init_copy.obj mp_init_i32.obj mp_init_i64.obj \ -mp_init_l.obj mp_init_multi.obj mp_init_set.obj mp_init_size.obj mp_init_u32.obj mp_init_u64.obj mp_init_ul.obj \ -mp_invmod.obj mp_is_square.obj mp_kronecker.obj mp_lcm.obj mp_log.obj mp_log_n.obj mp_lshd.obj mp_mod.obj mp_mod_2d.obj \ -mp_montgomery_calc_normalization.obj mp_montgomery_reduce.obj mp_montgomery_setup.obj mp_mul.obj mp_mul_2.obj \ -mp_mul_2d.obj mp_mul_d.obj mp_mulmod.obj mp_neg.obj mp_or.obj mp_pack.obj mp_pack_count.obj mp_prime_fermat.obj \ -mp_prime_frobenius_underwood.obj mp_prime_is_prime.obj mp_prime_miller_rabin.obj mp_prime_next_prime.obj \ -mp_prime_rabin_miller_trials.obj mp_prime_rand.obj mp_prime_strong_lucas_selfridge.obj mp_radix_size.obj \ -mp_radix_size_overestimate.obj mp_rand.obj mp_rand_source.obj mp_read_radix.obj mp_reduce.obj mp_reduce_2k.obj \ -mp_reduce_2k_l.obj mp_reduce_2k_setup.obj mp_reduce_2k_setup_l.obj mp_reduce_is_2k.obj mp_reduce_is_2k_l.obj \ -mp_reduce_setup.obj mp_root_n.obj mp_rshd.obj mp_sbin_size.obj mp_set.obj mp_set_double.obj mp_set_i32.obj mp_set_i64.obj \ -mp_set_l.obj mp_set_u32.obj mp_set_u64.obj mp_set_ul.obj mp_shrink.obj mp_signed_rsh.obj mp_sqrmod.obj mp_sqrt.obj \ -mp_sqrtmod_prime.obj mp_sub.obj mp_sub_d.obj mp_submod.obj mp_to_radix.obj mp_to_sbin.obj mp_to_ubin.obj mp_ubin_size.obj \ -mp_unpack.obj mp_warray_free.obj mp_xor.obj mp_zero.obj s_mp_add.obj s_mp_copy_digs.obj s_mp_div_3.obj \ -s_mp_div_recursive.obj s_mp_div_school.obj s_mp_div_small.obj s_mp_exptmod.obj s_mp_exptmod_fast.obj s_mp_fp_log.obj \ -s_mp_fp_log_d.obj s_mp_get_bit.obj s_mp_invmod.obj s_mp_invmod_odd.obj s_mp_log_2expt.obj \ -s_mp_montgomery_reduce_comba.obj s_mp_mul.obj s_mp_mul_balance.obj s_mp_mul_comba.obj s_mp_mul_high.obj \ -s_mp_mul_high_comba.obj s_mp_mul_karatsuba.obj s_mp_mul_toom.obj s_mp_prime_is_divisible.obj s_mp_prime_tab.obj \ -s_mp_radix_map.obj s_mp_radix_size_overestimate.obj s_mp_rand_platform.obj s_mp_rand_source.obj s_mp_sqr.obj \ -s_mp_sqr_comba.obj s_mp_sqr_karatsuba.obj s_mp_sqr_toom.obj s_mp_sub.obj s_mp_warray.obj s_mp_warray_get.obj \ -s_mp_warray_put.obj s_mp_zero_buf.obj s_mp_zero_digs.obj +mp_error_to_string.obj mp_exch.obj mp_expt_n.obj mp_exptmod.obj mp_exteuclid.obj mp_fprintf.obj mp_fread.obj \ +mp_from_sbin.obj mp_from_ubin.obj mp_fwrite.obj mp_gcd.obj mp_get_double.obj mp_get_i32.obj mp_get_i64.obj mp_get_l.obj \ +mp_get_mag_u32.obj mp_get_mag_u64.obj mp_get_mag_ul.obj mp_grow.obj mp_hash.obj mp_init.obj mp_init_copy.obj \ +mp_init_i32.obj mp_init_i64.obj mp_init_l.obj mp_init_multi.obj mp_init_set.obj mp_init_size.obj mp_init_u32.obj \ +mp_init_u64.obj mp_init_ul.obj mp_invmod.obj mp_is_square.obj mp_kronecker.obj mp_lcm.obj mp_log.obj mp_log_n.obj mp_lshd.obj \ +mp_mod.obj mp_mod_2d.obj mp_montgomery_calc_normalization.obj mp_montgomery_reduce.obj mp_montgomery_setup.obj \ +mp_mul.obj mp_mul_2.obj mp_mul_2d.obj mp_mul_d.obj mp_mulmod.obj mp_neg.obj mp_or.obj mp_pack.obj mp_pack_count.obj \ +mp_prime_fermat.obj mp_prime_frobenius_underwood.obj mp_prime_is_prime.obj mp_prime_miller_rabin.obj \ +mp_prime_next_prime.obj mp_prime_rabin_miller_trials.obj mp_prime_rand.obj mp_prime_strong_lucas_selfridge.obj \ +mp_radix_size.obj mp_radix_size_overestimate.obj mp_rand.obj mp_rand_source.obj mp_read_radix.obj mp_reduce.obj \ +mp_reduce_2k.obj mp_reduce_2k_l.obj mp_reduce_2k_setup.obj mp_reduce_2k_setup_l.obj mp_reduce_is_2k.obj \ +mp_reduce_is_2k_l.obj mp_reduce_setup.obj mp_root_n.obj mp_rshd.obj mp_sbin_size.obj mp_set.obj mp_set_double.obj \ +mp_set_i32.obj mp_set_i64.obj mp_set_l.obj mp_set_u32.obj mp_set_u64.obj mp_set_ul.obj mp_shrink.obj mp_signed_rsh.obj \ +mp_sqrmod.obj mp_sqrt.obj mp_sqrtmod_prime.obj mp_sub.obj mp_sub_d.obj mp_submod.obj mp_to_radix.obj mp_to_sbin.obj \ +mp_to_ubin.obj mp_ubin_size.obj mp_unpack.obj mp_warray_free.obj mp_xor.obj mp_zero.obj s_mp_add.obj s_mp_copy_digs.obj \ +s_mp_div_3.obj s_mp_div_recursive.obj s_mp_div_school.obj s_mp_div_small.obj s_mp_exptmod.obj s_mp_exptmod_fast.obj \ +s_mp_fp_log.obj s_mp_fp_log_d.obj s_mp_fprint.obj s_mp_get_bit.obj s_mp_invmod.obj s_mp_invmod_odd.obj \ +s_mp_log_2expt.obj s_mp_montgomery_reduce_comba.obj s_mp_mul.obj s_mp_mul_balance.obj s_mp_mul_comba.obj \ +s_mp_mul_high.obj s_mp_mul_high_comba.obj s_mp_mul_karatsuba.obj s_mp_mul_toom.obj s_mp_parse_printf_token.obj \ +s_mp_prime_is_divisible.obj s_mp_prime_tab.obj s_mp_radix_map.obj s_mp_radix_size_overestimate.obj \ +s_mp_rand_platform.obj s_mp_rand_source.obj s_mp_sprint.obj s_mp_sqr.obj s_mp_sqr_comba.obj s_mp_sqr_karatsuba.obj \ +s_mp_sqr_toom.obj s_mp_sub.obj s_mp_warray.obj s_mp_warray_get.obj s_mp_warray_put.obj s_mp_zero_buf.obj \ +s_mp_zero_digs.obj HEADERS_PUB=tommath.h HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB) diff --git a/makefile.shared b/makefile.shared index 20bd8e03..43236a79 100644 --- a/makefile.shared +++ b/makefile.shared @@ -26,28 +26,29 @@ LCOV_ARGS=--directory .libs --directory . OBJECTS=mp_2expt.o mp_abs.o mp_add.o mp_add_d.o mp_addmod.o mp_and.o mp_clamp.o mp_clear.o mp_clear_multi.o \ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count_bits.o mp_cutoffs.o \ mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \ -mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \ -mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \ -mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \ -mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \ -mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \ -mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \ -mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ -mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ -mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o \ -mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o \ -mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o \ -mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o mp_sqrmod.o mp_sqrt.o \ -mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o \ -mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o s_mp_div_3.o \ -s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_fp_log.o \ -s_mp_fp_log_d.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log_2expt.o \ -s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o s_mp_mul_high.o \ -s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o s_mp_prime_tab.o \ -s_mp_radix_map.o s_mp_radix_size_overestimate.o s_mp_rand_platform.o s_mp_rand_source.o s_mp_sqr.o \ -s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o \ -s_mp_warray_put.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fprintf.o mp_fread.o \ +mp_from_sbin.o mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o \ +mp_get_mag_u32.o mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o \ +mp_init_i32.o mp_init_i64.o mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o \ +mp_init_u64.o mp_init_ul.o mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o \ +mp_mod.o mp_mod_2d.o mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o \ +mp_mul.o mp_mul_2.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o \ +mp_prime_fermat.o mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o \ +mp_prime_next_prime.o mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o \ +mp_radix_size.o mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o \ +mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \ +mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \ +mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o \ +mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \ +mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o \ +s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o \ +s_mp_fp_log.o s_mp_fp_log_d.o s_mp_fprint.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o \ +s_mp_log_2expt.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ +s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_parse_printf_token.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_platform.o s_mp_rand_source.o s_mp_sprint.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o \ +s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o s_mp_warray_put.o s_mp_zero_buf.o \ +s_mp_zero_digs.o #END_INS diff --git a/makefile.unix b/makefile.unix index 06dadddb..6f389f1c 100644 --- a/makefile.unix +++ b/makefile.unix @@ -32,28 +32,29 @@ LIBMAIN_S = libtommath.a OBJECTS=mp_2expt.o mp_abs.o mp_add.o mp_add_d.o mp_addmod.o mp_and.o mp_clamp.o mp_clear.o mp_clear_multi.o \ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count_bits.o mp_cutoffs.o \ mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \ -mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \ -mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \ -mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \ -mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \ -mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \ -mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \ -mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \ -mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \ -mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o mp_radix_size.o \ -mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o mp_reduce_2k.o \ -mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o mp_reduce_is_2k_l.o \ -mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o mp_set_i32.o mp_set_i64.o \ -mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o mp_sqrmod.o mp_sqrt.o \ -mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o mp_to_ubin.o mp_ubin_size.o \ -mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o s_mp_div_3.o \ -s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o s_mp_fp_log.o \ -s_mp_fp_log_d.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o s_mp_log_2expt.o \ -s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o s_mp_mul_high.o \ -s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_prime_is_divisible.o s_mp_prime_tab.o \ -s_mp_radix_map.o s_mp_radix_size_overestimate.o s_mp_rand_platform.o s_mp_rand_source.o s_mp_sqr.o \ -s_mp_sqr_comba.o s_mp_sqr_karatsuba.o s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o \ -s_mp_warray_put.o s_mp_zero_buf.o s_mp_zero_digs.o +mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fprintf.o mp_fread.o \ +mp_from_sbin.o mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o \ +mp_get_mag_u32.o mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o \ +mp_init_i32.o mp_init_i64.o mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o \ +mp_init_u64.o mp_init_ul.o mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log.o mp_log_n.o mp_lshd.o \ +mp_mod.o mp_mod_2d.o mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o \ +mp_mul.o mp_mul_2.o mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o \ +mp_prime_fermat.o mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o \ +mp_prime_next_prime.o mp_prime_rabin_miller_trials.o mp_prime_rand.o mp_prime_strong_lucas_selfridge.o \ +mp_radix_size.o mp_radix_size_overestimate.o mp_rand.o mp_rand_source.o mp_read_radix.o mp_reduce.o \ +mp_reduce_2k.o mp_reduce_2k_l.o mp_reduce_2k_setup.o mp_reduce_2k_setup_l.o mp_reduce_is_2k.o \ +mp_reduce_is_2k_l.o mp_reduce_setup.o mp_root_n.o mp_rshd.o mp_sbin_size.o mp_set.o mp_set_double.o \ +mp_set_i32.o mp_set_i64.o mp_set_l.o mp_set_u32.o mp_set_u64.o mp_set_ul.o mp_shrink.o mp_signed_rsh.o \ +mp_sqrmod.o mp_sqrt.o mp_sqrtmod_prime.o mp_sub.o mp_sub_d.o mp_submod.o mp_to_radix.o mp_to_sbin.o \ +mp_to_ubin.o mp_ubin_size.o mp_unpack.o mp_warray_free.o mp_xor.o mp_zero.o s_mp_add.o s_mp_copy_digs.o \ +s_mp_div_3.o s_mp_div_recursive.o s_mp_div_school.o s_mp_div_small.o s_mp_exptmod.o s_mp_exptmod_fast.o \ +s_mp_fp_log.o s_mp_fp_log_d.o s_mp_fprint.o s_mp_get_bit.o s_mp_invmod.o s_mp_invmod_odd.o \ +s_mp_log_2expt.o s_mp_montgomery_reduce_comba.o s_mp_mul.o s_mp_mul_balance.o s_mp_mul_comba.o \ +s_mp_mul_high.o s_mp_mul_high_comba.o s_mp_mul_karatsuba.o s_mp_mul_toom.o s_mp_parse_printf_token.o \ +s_mp_prime_is_divisible.o s_mp_prime_tab.o s_mp_radix_map.o s_mp_radix_size_overestimate.o \ +s_mp_rand_platform.o s_mp_rand_source.o s_mp_sprint.o s_mp_sqr.o s_mp_sqr_comba.o s_mp_sqr_karatsuba.o \ +s_mp_sqr_toom.o s_mp_sub.o s_mp_warray.o s_mp_warray_get.o s_mp_warray_put.o s_mp_zero_buf.o \ +s_mp_zero_digs.o HEADERS_PUB=tommath.h diff --git a/mp_fprintf.c b/mp_fprintf.c new file mode 100644 index 00000000..26f98fb3 --- /dev/null +++ b/mp_fprintf.c @@ -0,0 +1,680 @@ +#include "tommath_private.h" +#ifdef MP_FPRINTF_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_NO_FILE +#ifdef MP_WITH_MP_FPRINTF +/* At most 2*int (might be 64 bit) -> 2*20 plus + some change, so 128 should more than enough */ +#define MP_FPRINTF_BUF_LEN 128 +int mp_fprintf(FILE *stream, const char *s, ...) +{ + mp_err err = MP_OKAY; + printf_token token; + va_list args; + char buf[MP_FPRINTF_BUF_LEN]; + ptrdiff_t len; + int i, count = 0; + int *enn = NULL; + size_t maxlen; + int printed = 0; + bool valid_token = false; + mp_int t; + + /* For the people who switch off all compiler warnings */ + if (s == NULL) { + return -1; + } + + if ((err = mp_init(&t)) != MP_OKAY) { + return -1; + } + + va_start(args, s); + + while ((*s) != '\0') { + if (*s == '%') { + valid_token = s_mp_parse_printf_token(s, &token); + if (!valid_token) { + printed = -1; + goto LTM_ERR; + } + len = token.end_ptr - token.start_ptr; + /* TODO: Can that even happen if parse_printf_token returns true? */ + if (len == 0) { + printed = -1; + goto LTM_ERR; + } + /* Aren't we already there? */ + s = token.start_ptr; + /* Put the whole thing in a buffer and let fprintf do the heavy work */ + for (i = 0; i < (int) len; i++) { + buf[i] = *s; + s++; + } + buf[i] = '\0'; + + switch (token.specifier) { + case 'd': + case 'i': + switch (token.length) { + case LEN_h: + /* Integer promotion: never smaller than an int/double (7.16.1.1 "The va_arg macro" par. 2) */ + count = fprintf(stream, buf, va_arg(args, int)); + if (count >= 0) { + printed += count; + } else { + /* fprintf() will set errno/ferror() accordingly */ + printed = count; + goto LTM_ERR; + } + break; + case LEN_hh: + count = fprintf(stream, buf, va_arg(args, int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_l: + count = fprintf(stream, buf, va_arg(args, long int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_ll: + count = fprintf(stream, buf, va_arg(args, long long int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_j: + count = fprintf(stream, buf, va_arg(args, intmax_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_z: /*TODO: error?*/ + count = fprintf(stream, buf, va_arg(args, size_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_t: + count = fprintf(stream, buf, va_arg(args, ptrdiff_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_Z: + maxlen = 0; + if (token.width > 0) { + maxlen = (size_t)token.width; + } + if (token.width == MP_PRINTF_DYNAMIC) { + mp_set(&t, 0u); + if ((err = mp_copy(va_arg(args, mp_int *),&t)) != MP_OKAY) goto LTM_ERR; + count = s_mp_fprint(&t, (size_t)va_arg(args, int), token.flags, 10, stream); + } else { + count = s_mp_fprint(va_arg(args, mp_int *), maxlen, token.flags, 10, stream); + } + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + default: + count = fprintf(stream, buf, va_arg(args, int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + } + break; + case 'u': + switch (token.length) { + case LEN_h: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_hh: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_l: + count = fprintf(stream, buf, va_arg(args, long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_ll: + count = fprintf(stream, buf, va_arg(args, long long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_j: + count = fprintf(stream, buf, va_arg(args, uintmax_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_z: + count = fprintf(stream, buf, va_arg(args, size_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_t: + count = fprintf(stream, buf, va_arg(args, ptrdiff_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_Z: + /* This is unsigned, show absolute value? */ + maxlen = 0; + if (token.width > 0) { + maxlen = (size_t)token.width; + } + if (token.width == MP_PRINTF_DYNAMIC) { + mp_set(&t, 0u); + if ((err = mp_copy(va_arg(args, mp_int *), &t)) != MP_OKAY) goto LTM_ERR; + count = s_mp_fprint(&t, (size_t)va_arg(args, int), token.flags, 10, stream); + } else { + count = s_mp_fprint(va_arg(args, mp_int *), maxlen, token.flags, 10, stream); + } + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + default: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + break; + } + break; + case 'o': + switch (token.length) { + case LEN_h: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_hh: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_l: + count = fprintf(stream, buf, va_arg(args, long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_ll: + count = fprintf(stream, buf, va_arg(args, long long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_j: + count = fprintf(stream, buf, va_arg(args, uintmax_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_z: + count = fprintf(stream, buf, va_arg(args, size_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_t: + count = fprintf(stream, buf, va_arg(args, ptrdiff_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_Z: + maxlen = 0; + if (token.width > 0) { + maxlen = (size_t)token.width; + } + if (token.width == MP_PRINTF_DYNAMIC) { + mp_set(&t, 0u); + if ((err = mp_copy(va_arg(args, mp_int *),&t)) != MP_OKAY) goto LTM_ERR; + count = s_mp_fprint(&t, (size_t)va_arg(args, int), token.flags, 8, stream); + } else { + count = s_mp_fprint(va_arg(args, mp_int *), maxlen, token.flags, 8, stream); + } + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + default: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + } + break; + + case 'x': + case 'X': + switch (token.length) { + case LEN_h: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_hh: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_l: + count = fprintf(stream, buf, va_arg(args, long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_ll: + count = fprintf(stream, buf, va_arg(args, long long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_j: + count = fprintf(stream, buf, va_arg(args, uintmax_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_z: + count = fprintf(stream, buf, va_arg(args, size_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_t: + count = fprintf(stream, buf, va_arg(args, ptrdiff_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_Z: + /* TODO: add upper-/lowercase */ + maxlen = 0; + if (token.width > 0) { + maxlen = (size_t)token.width; + } + if (token.width == MP_PRINTF_DYNAMIC) { + mp_set(&t, 0u); + if ((err = mp_copy(va_arg(args, mp_int *), &t)) != MP_OKAY) goto LTM_ERR; + count = s_mp_fprint(&t, (size_t)va_arg(args, int), token.flags, 16, stream); + } else { + count = s_mp_fprint(va_arg(args, mp_int *), maxlen, token.flags, 16, stream); + } + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + default: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + } + break; + /* Has been added lately (C23) to the standard */ + case 'b': + case 'B': + switch (token.length) { +#if ( __STDC_VERSION__ >= 202000 ) + case LEN_h: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_hh: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_l: + count = fprintf(stream, buf, va_arg(args, long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_ll: + count = fprintf(stream, buf, va_arg(args, long long unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_j: + count = fprintf(stream, buf, va_arg(args, uintmax_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_z: + count = fprintf(stream, buf, va_arg(args, size_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case LEN_t: + count = fprintf(stream, buf, va_arg(args, ptrdiff_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; +#endif + case LEN_Z: + maxlen = 0; + if (token.width > 0) { + maxlen = (size_t)token.width; + } + if (token.width == MP_PRINTF_DYNAMIC) { + mp_set(&t, 0u); + if ((err = mp_copy(va_arg(args, mp_int *),&t)) != MP_OKAY) goto LTM_ERR; + count = s_mp_fprint(&t, (size_t)va_arg(args, int), token.flags, 2, stream); + } else { + mp_set(&t, 0u); + count = s_mp_fprint(va_arg(args, mp_int *), maxlen, token.flags, 2, stream); + } + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + default: + count = fprintf(stream, buf, va_arg(args, unsigned int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + } + break; + case 'K': + switch (token.length) { + case LEN_Z: + maxlen = 0; + if (token.width > 0) { + maxlen = (size_t)token.width; + } + if (token.width == MP_PRINTF_DYNAMIC) { + mp_set(&t, 0u); + if ((err = mp_copy(va_arg(args, mp_int *),&t)) != MP_OKAY) goto LTM_ERR; + count = s_mp_fprint(&t, (size_t)va_arg(args, int), token.flags, 64, stream); + } else { + count = s_mp_fprint(va_arg(args, mp_int *), maxlen, token.flags, 64, stream); + } + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + default: + break; + } + break; + case 'c': + if (token.length == LEN_l) { + count = fprintf(stream, buf, va_arg(args, wint_t)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + } else { + count = fprintf(stream, buf, va_arg(args, int)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + } + break; + case 's': + if (token.length == LEN_l) { + count = fprintf(stream, buf, va_arg(args, const wint_t *)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + } else { + count = fprintf(stream, buf, va_arg(args, const char *)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + } + break; + case 'p': + count = fprintf(stream, buf, va_arg(args, void *)); + if (count >= 0) { + printed += count; + } + break; + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'a': + case 'A': + if (token.length == LEN_L) { + count = fprintf(stream, buf, va_arg(args, long double)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + } else { + count = fprintf(stream, buf, va_arg(args, double)); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + } + break; + case '%': + count = fprintf(stream, buf, '%'); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + case 'n': + /* No output says the standard */ + enn = va_arg(args, int *); + *enn = printed; + break; + default: + count = fprintf(stream, " unkown specifier: %c\n",token.specifier); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + break; + } + } + count = fprintf(stream, "%c",*s); + if (count >= 0) { + printed += count; + } else { + printed = count; + goto LTM_ERR; + } + s++; + } +LTM_ERR: + if (err != MP_OKAY) { + printed = -1; + } + mp_clear(&t); + va_end(args); + return printed; +} + +#endif +#endif +#endif diff --git a/s_mp_fprint.c b/s_mp_fprint.c new file mode 100644 index 00000000..a5877dd2 --- /dev/null +++ b/s_mp_fprint.c @@ -0,0 +1,36 @@ +#include "tommath_private.h" +#ifdef S_MP_FPRINT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_NO_FILE +#ifdef MP_WITH_MP_FPRINTF +int s_mp_fprint(const mp_int *a, size_t maxlen, unsigned int flags, int radix, FILE *stream) +{ + char *buffer = NULL; + int written = 0, printed = -1; + + written = s_mp_sprint(a, maxlen, flags, radix, &buffer); + if (written < 0) { + goto LTM_ERR; + } + if (buffer != NULL) { + printed = fprintf(stream,"%s", buffer); + } + if (printed < 0) { + written = printed; + goto LTM_ERR; + } + printed++; + if (written != printed) { + /* fprintf(stderr, "written (%d) != printed (%d)\n", written, printed); */ + goto LTM_ERR; + } + +LTM_ERR: + MP_FREE_BUF(buffer, (size_t)written); + return written; +} +#endif +#endif +#endif diff --git a/s_mp_parse_printf_token.c b/s_mp_parse_printf_token.c new file mode 100644 index 00000000..cb5e75c6 --- /dev/null +++ b/s_mp_parse_printf_token.c @@ -0,0 +1,157 @@ +#include "tommath_private.h" +#ifdef S_MP_PARSE_PRINTF_TOKEN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_NO_FILE +#ifdef MP_WITH_MP_FPRINTF +/* Parses a single(!) format specifier */ +bool s_mp_parse_printf_token(const char *format, printf_token *token) +{ + bool match; + /* TODO: Linear search for verification. switch to a switch? */ + /* Extra specifiers for bigint only: 'b', 'B' for binary output + (also in C23 now) and 'K' (uppercase 'k') for base 64. + */ + const char *specifiers = "iduopxXcsfFgGeEtpaAnbBK%"; + const char *p = format + 1; + int i; + + if ((format == NULL) || (*format != '%')) { + return false; + } + + token->start_ptr = format; + token->flags = 0; + token->width = MP_PRINTF_OMITTED; + token->precision = MP_PRINTF_OMITTED; + token->length = LEN_NONE; + token->specifier = '\0'; + + + while (*p) { + if (*p == '-') { + token->flags |= FLAG_LEFT_JUSTIFY; + } else if (*p == '+') { + token->flags |= FLAG_FORCE_SIGN; + } else if (*p == ' ') { + token->flags |= FLAG_SPACE_SIGN; + } else if (*p == '#') { + token->flags |= FLAG_HASH; + } else if (*p == '0') { + token->flags |= FLAG_ZERO_PAD; + } else { + break; + } + p++; + } + + + if (*p == '*') { + token->width = MP_PRINTF_DYNAMIC; + p++; + } else if (isdigit((unsigned char)*p)) { + token->width = 0; + /* TODO: check length and use itoa */ + while (isdigit((unsigned char)*p)) { + token->width = token->width * 10 + (*p - '0'); + p++; + } + } + + + if (*p == '.') { + p++; + if (*p == '*') { + token->precision = MP_PRINTF_DYNAMIC; + p++; + } else { + token->precision = 0; + /* TODO: check length and use itoa? */ + while (isdigit((unsigned char)*p)) { + token->precision = token->precision * 10 + (*p - '0'); + p++; + } + } + } + + /* The C23 modifiers (wN, wfN) are not implemented. Yet. + They are the types listed in stdint.h as intN_t + and uintN_t respectively for "wN" and int_fastN_t + and uint_fastN_t respectively for "wfN". + "H", "D", and "DD" for the _DecimalN are not + implemented. Mainly because compiler support is + also, let's say, incomplete. + */ + switch (*p) { + case 'h': + if (*(p + 1) == 'h') { + token->length = LEN_hh; + p += 2; + } else { + token->length = LEN_h; + p++; + } + break; + case'l': + if (*(p + 1) == 'l') { + token->length = LEN_ll; + p += 2; + } else { + token->length = LEN_l; + p++; + } + break; + case 'j': + token->length = LEN_j; + p++; + break; + case 't': + token->length = LEN_t; + p++; + break; + case 'z': + token->length = LEN_z; + p++; + break; + case 'L': + token->length = LEN_L; + p++; + break; + case 'Z': + token->length = LEN_Z; + p++; + break; + } + + + if (*p == '\0') { + return false; + } + + match = true; + /* Only check for validity now, details in the main loop */ + for (i = 0;; i++) { + if (*p == '\0') { + match = false; + break; + } + if (*p == specifiers[i]) { + break; + } + } + + if (match) { + token->specifier = *p; + p++; + token->end_ptr = p; + return true; + } + + return false; +} + + +#endif +#endif +#endif diff --git a/s_mp_sprint.c b/s_mp_sprint.c new file mode 100644 index 00000000..90d2f271 --- /dev/null +++ b/s_mp_sprint.c @@ -0,0 +1,158 @@ +#include "tommath_private.h" +#ifdef S_MP_SPRINT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + + + +#ifndef MP_NO_FILE +#ifdef MP_WITH_MP_FPRINTF +/* Print a formatted big integer to a string buffer. + + Basically mp_fwrite() with a limit. Here maxlen is the printf "width". + Use of "precision" does not make much sense, if we don't use scientific + notation. + There is a possibility to use a representation of the form + ddddd"..."dddd + That is the "width" number of digits and the "precision" number of digits + at the end visually connected by an ellipsis (three periods). + Currently only "width" is implemented. + + TODO: According to standard: + On success, the total number of characters written is returned. + If a writing error occurs, the error indicator (ferror) is set + and a negative number is returned. + If a multibyte character encoding error occurs while writing + wide characters, errno is set to EILSEQ and a negative + number is returned. + + TODO: offer a mp_snprintf(), too? + */ +int s_mp_sprint(const mp_int *a, size_t maxlen, unsigned int flags, int radix, char **formatted) +{ + char *buf, *cbuf; + mp_err err; + size_t size, written, mlen, extra = 0; + int r = 0, i; + bool prefix = false, forced_sign = false, space_sign = false, left_justify = false, zero_pad = false; + + + if (flags & FLAG_FORCE_SIGN) { + forced_sign = true; + extra++; + } + if (flags & FLAG_SPACE_SIGN) { + space_sign = true; + extra++; + } + if (flags & FLAG_HASH) { + prefix = true; + extra +=2; + } + if (flags & FLAG_LEFT_JUSTIFY) { + left_justify = true; + } + if (flags & FLAG_ZERO_PAD) { + zero_pad = true; + } + + /* We need the exact value here. */ + if ((err = mp_radix_size(a, radix, &size)) != MP_OKAY) { + return err; + } + if (maxlen > 0) { + mlen = maxlen; + } else { + mlen = size; + } + + /* We have the exact number of digits and the limit "mlen", + we can measure the padding needed and allocate accordingly */ + if ((mlen > size) && (left_justify || zero_pad)) { + /* we need padding for the difference between mlen and size */ + extra += mlen - size; + } + + buf = (char *) MP_MALLOC(size + extra); + if (buf == NULL) { + return MP_MEM; + } + /* Why put it in the buffer instead of just printing it? For the s(n)printf() coming next */ + cbuf = buf; + + /* Padding with spaces comes first */ + if (left_justify) { + for (i = 0; i< (int)(mlen - size); i++) { + *buf = (char) ' '; + buf++; + r++; + } + } + if (space_sign && !mp_isneg(a)) { + *buf = (char) ' '; + buf++; + r++; + } + if (forced_sign && !mp_isneg(a)) { + *buf = (char) '+'; + buf++; + r++; + } + + /* Is there a prefix for base64? Would it be useful to invent one? + (I like "@", it's ASCII and distinct) */ + if (prefix) { + switch (radix) { + case 2 : + *buf = (char) '0'; + buf++; + r++; + *buf = (char) 'b'; + buf++; + r++; + break; + case 8 : + *buf = (char) '0'; + buf++; + r++; + break; + case 16: + *buf = (char) '0'; + buf++; + r++; + *buf = (char) 'x'; + buf++; + r++; + break; + } + } + + /* Padding with zeros comes after the prefix */ + if (zero_pad) { + for (i = 0; i< (int)(mlen - size); i++) { + *buf = (char) '0'; + buf++; + r++; + } + } + *buf = (char) '\0'; + + if ((err = mp_to_radix(a, buf, size, &written, radix)) == MP_OKAY) { + *formatted = cbuf; + } + + if (err != MP_OKAY) { + return -1; + } else { + if ((maxlen > 0) && (maxlen < written)) { + r += (int)maxlen; + } else { + r += (int)written; + } + } + return r; +} + +#endif +#endif +#endif diff --git a/sources.cmake b/sources.cmake index ba3012ef..1f47a9b8 100644 --- a/sources.cmake +++ b/sources.cmake @@ -31,6 +31,7 @@ mp_exch.c mp_expt_n.c mp_exptmod.c mp_exteuclid.c +mp_fprintf.c mp_fread.c mp_from_sbin.c mp_from_ubin.c @@ -135,6 +136,7 @@ s_mp_exptmod.c s_mp_exptmod_fast.c s_mp_fp_log.c s_mp_fp_log_d.c +s_mp_fprint.c s_mp_get_bit.c s_mp_invmod.c s_mp_invmod_odd.c @@ -147,12 +149,14 @@ s_mp_mul_high.c s_mp_mul_high_comba.c s_mp_mul_karatsuba.c s_mp_mul_toom.c +s_mp_parse_printf_token.c s_mp_prime_is_divisible.c s_mp_prime_tab.c s_mp_radix_map.c s_mp_radix_size_overestimate.c s_mp_rand_platform.c s_mp_rand_source.c +s_mp_sprint.c s_mp_sqr.c s_mp_sqr_comba.c s_mp_sqr_karatsuba.c diff --git a/testme.sh b/testme.sh index 92997a04..d7c741c6 100755 --- a/testme.sh +++ b/testme.sh @@ -16,7 +16,8 @@ else fi ret=0 -TEST_CFLAGS="" +# Test mp_fprintf, too, even if not included explicitly +TEST_CFLAGS=" -DMP_WITH_MP_FPRINTF " _help() { @@ -112,14 +113,14 @@ _fixup_cflags() { case "$compiler_version" in clang*=4.2.1) # one of my versions of clang complains about some stuff in stdio.h and stdarg.h ... - TEST_CFLAGS="-Wno-typedef-redefinition" + TEST_CFLAGS+=" -Wno-typedef-redefinition " ;; gcc*=9) # gcc 9 seems to sometimes think that variables are uninitialized, but they are. - TEST_CFLAGS="-Wno-maybe-uninitialized" + TEST_CFLAGS+=" -Wno-maybe-uninitialized " ;; *) - TEST_CFLAGS="" + TEST_CFLAGS+="" ;; esac echo $compiler_version @@ -343,7 +344,7 @@ fi if [[ "$CHECK_SYMBOLS" == "1" ]] then - make -f makefile.shared + CFLAGS=" -DMP_WITH_MP_FPRINTF " make -f makefile.shared cat << EOF diff --git a/tommath.def b/tommath.def index ed5aa8b0..ce47fa85 100644 --- a/tommath.def +++ b/tommath.def @@ -34,6 +34,7 @@ EXPORTS mp_expt_n mp_exptmod mp_exteuclid + mp_fprintf mp_fread mp_from_sbin mp_from_ubin diff --git a/tommath.h b/tommath.h index 1820d243..f6f5055c 100644 --- a/tommath.h +++ b/tommath.h @@ -586,6 +586,11 @@ mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size #ifndef MP_NO_FILE mp_err mp_fread(mp_int *a, int radix, FILE *stream) MP_WUR; mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) MP_WUR; +#ifdef MP_WITH_MP_FPRINTF +/* Supposed to work like a normal fprintf returning number of characters written or a negative value */ +int mp_fprintf(FILE *stream, const char *s, ...); +/* int snprintf(char *str, size_t size, const char *format, ...); */ +#endif #endif int mp_warray_free(void); diff --git a/tommath_c89.h b/tommath_c89.h index 22436366..dab5ec09 100644 --- a/tommath_c89.h +++ b/tommath_c89.h @@ -32,6 +32,10 @@ typedef __UINT64_TYPE__ mp_uintptr; typedef __UINT32_TYPE__ mp_uintptr; # endif +typedef __INTMAX_TYPE__ intmax_t; +typedef __UINTMAX_TYPE__ uintmax_t; + + /* inttypes.h replacement, printf format specifier */ # if __WORDSIZE == 64 # define MP_PRI64_PREFIX "l" diff --git a/tommath_class.h b/tommath_class.h index 40ddfd4b..6536277c 100644 --- a/tommath_class.h +++ b/tommath_class.h @@ -40,6 +40,7 @@ # define MP_EXPT_N_C # define MP_EXPTMOD_C # define MP_EXTEUCLID_C +# define MP_FPRINTF_C # define MP_FREAD_C # define MP_FROM_SBIN_C # define MP_FROM_UBIN_C @@ -144,6 +145,7 @@ # define S_MP_EXPTMOD_FAST_C # define S_MP_FP_LOG_C # define S_MP_FP_LOG_D_C +# define S_MP_FPRINT_C # define S_MP_GET_BIT_C # define S_MP_INVMOD_C # define S_MP_INVMOD_ODD_C @@ -156,12 +158,14 @@ # define S_MP_MUL_HIGH_COMBA_C # define S_MP_MUL_KARATSUBA_C # define S_MP_MUL_TOOM_C +# define S_MP_PARSE_PRINTF_TOKEN_C # define S_MP_PRIME_IS_DIVISIBLE_C # define S_MP_PRIME_TAB_C # define S_MP_RADIX_MAP_C # define S_MP_RADIX_SIZE_OVERESTIMATE_C # define S_MP_RAND_PLATFORM_C # define S_MP_RAND_SOURCE_C +# define S_MP_SPRINT_C # define S_MP_SQR_C # define S_MP_SQR_COMBA_C # define S_MP_SQR_KARATSUBA_C @@ -330,6 +334,9 @@ # define MP_SUB_C #endif +#if defined(MP_FPRINTF_C) +#endif + #if defined(MP_FREAD_C) # define MP_ADD_D_C # define MP_MUL_D_C @@ -1104,6 +1111,9 @@ # define S_MP_FP_LOG_FRACTION_D_C #endif +#if defined(S_MP_FPRINT_C) +#endif + #if defined(S_MP_GET_BIT_C) #endif @@ -1225,6 +1235,9 @@ # define S_MP_DIV_3_C #endif +#if defined(S_MP_PARSE_PRINTF_TOKEN_C) +#endif + #if defined(S_MP_PRIME_IS_DIVISIBLE_C) # define MP_DIV_D_C #endif @@ -1253,6 +1266,9 @@ # define S_MP_RAND_PLATFORM_C #endif +#if defined(S_MP_SPRINT_C) +#endif + #if defined(S_MP_SQR_C) # define MP_CLAMP_C # define MP_CLEAR_C diff --git a/tommath_private.h b/tommath_private.h index be620dbc..f5fe4ef3 100644 --- a/tommath_private.h +++ b/tommath_private.h @@ -234,6 +234,69 @@ MP_PRIVATE mp_err s_mp_radix_size_overestimate(const mp_int *a, const int radix, MP_PRIVATE mp_err s_mp_fp_log(const mp_int *a, mp_int *c) MP_WUR; MP_PRIVATE mp_err s_mp_fp_log_d(const mp_int *a, mp_word *c) MP_WUR; + +#ifndef MP_NO_FILE +#ifdef MP_WITH_MP_FPRINTF +#include +#include +#include + +/* TODO: Quite a mix of storage methods (preproc, enum, struct,...), clean up! */ +#define FLAG_LEFT_JUSTIFY (1 << 0) /* '-' */ +#define FLAG_FORCE_SIGN (1 << 1) /* '+' */ +#define FLAG_SPACE_SIGN (1 << 2) /* ' ' */ +#define FLAG_HASH (1 << 3) /* '#' */ +#define FLAG_ZERO_PAD (1 << 4) /* '0' */ +/* TODO: would need locale. Implement nevertheless? */ +/* #define FLAG_THOUSAND_SEP (1 << 5) */ /* "'" */ + +/* Length Modifiers */ +/* + There are not many letters avaiable for extensions. The most logical + is 'Z' (also used by GMP for mpz) but that printf's manpage says "Do not use". + We don't care and use 'Z'. + Others are: + 'q' seems to be a synonym for 'll', 'Q' (uppercase q) is free, (used + by gmp for mpq), 'F' (uppercase 'f') is available (used by gmp for + floating point). 'M' (uppercase 'm') is used by gmp to print a limb, 'N' + (uppercase 'n') for the limbarray + + TODO: limb might be interesting, add? +*/ +typedef enum { + LEN_NONE, + LEN_h, /* short (or signed char if hh) */ + LEN_hh, /* char */ + LEN_l, /* long (or wchar_t) */ + LEN_ll, /* long long */ + LEN_j, /* intmax_t */ + LEN_z, /* size_t */ + LEN_t, /* ptrdiff_t */ + /* Check if the diy-dtoa algorithm supports long double + easily (ld-mantissa has 64 bits, so it is possible) */ + LEN_L, /* long double */ + LEN_Z /* arbitrary precision */ +} length_modifier; + +/* width/precision either not given or dynamic via '*' and argument */ +#define MP_PRINTF_OMITTED (-1) +#define MP_PRINTF_DYNAMIC (-2) +typedef struct { + unsigned int flags; + int width; + int precision; + length_modifier length; + char specifier; + const char *start_ptr; + const char *end_ptr; +} printf_token; + + +MP_PRIVATE bool s_mp_parse_printf_token(const char *format, printf_token *token); +MP_PRIVATE int s_mp_fprint(const mp_int *a, size_t maxlen, unsigned int flags, int radix, FILE *stream); +MP_PRIVATE int s_mp_sprint(const mp_int *a, size_t maxlen, unsigned int flags, int radix, char **formatted); +#endif +#endif #ifdef MP_SMALL_STACK_SIZE #if defined(__GNUC__)