output.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* output.c: bcmath library file. */
  2. /*
  3. Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
  4. Copyright (C) 2000 Philip A. Nelson
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details. (LICENSE)
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to:
  15. The Free Software Foundation, Inc.
  16. 59 Temple Place, Suite 330
  17. Boston, MA 02111-1307 USA.
  18. You may contact the author by:
  19. e-mail: philnelson@acm.org
  20. us-mail: Philip A. Nelson
  21. Computer Science Department, 9062
  22. Western Washington University
  23. Bellingham, WA 98226-9062
  24. *************************************************************************/
  25. #include <config.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <ctype.h>
  29. #include <stdarg.h>
  30. #include "bcmath.h"
  31. #include "private.h"
  32. /* The following routines provide output for bcd numbers package
  33. using the rules of POSIX bc for output. */
  34. /* This structure is used for saving digits in the conversion process. */
  35. typedef struct stk_rec {
  36. long digit;
  37. struct stk_rec *next;
  38. } stk_rec;
  39. /* The reference string for digits. */
  40. static char ref_str[] = "0123456789ABCDEF";
  41. /* A special output routine for "multi-character digits." Exactly
  42. SIZE characters must be output for the value VAL. If SPACE is
  43. non-zero, we must output one space before the number. OUT_CHAR
  44. is the actual routine for writing the characters. */
  45. void bc_out_long (long val, size_t size, bool space, void (*out_char)(char) )
  46. {
  47. char digits[40];
  48. size_t len, ix;
  49. if (space) (*out_char) (' ');
  50. snprintf(digits, sizeof(digits), "%ld", val);
  51. len = strlen (digits);
  52. while (size > len)
  53. {
  54. (*out_char) ('0');
  55. size--;
  56. }
  57. for (ix=0; ix < len; ix++)
  58. (*out_char) (digits[ix]);
  59. }
  60. /* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR
  61. as the routine to do the actual output of the characters. */
  62. void bc_out_num (bc_num num, int o_base, void (*out_char)(char), int leading_zero)
  63. {
  64. char *nptr;
  65. int index, fdigit;
  66. bool pre_space;
  67. stk_rec *digits, *temp;
  68. bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
  69. /* The negative sign if needed. */
  70. if (num->n_sign == MINUS) (*out_char) ('-');
  71. /* Output the number. */
  72. if (bc_is_zero (num))
  73. (*out_char) ('0');
  74. else
  75. if (o_base == 10)
  76. {
  77. /* The number is in base 10, do it the fast way. */
  78. nptr = num->n_value;
  79. if (num->n_len > 1 || *nptr != 0)
  80. for (index=num->n_len; index>0; index--)
  81. (*out_char) (BCD_CHAR(*nptr++));
  82. else
  83. nptr++;
  84. if (leading_zero && bc_is_zero (num))
  85. (*out_char) ('0');
  86. /* Now the fraction. */
  87. if (num->n_scale > 0)
  88. {
  89. (*out_char) ('.');
  90. for (index=0; index<num->n_scale; index++)
  91. (*out_char) (BCD_CHAR(*nptr++));
  92. }
  93. }
  94. else
  95. {
  96. /* special case ... */
  97. if (leading_zero && bc_is_zero (num))
  98. (*out_char) ('0');
  99. /* The number is some other base. */
  100. digits = NULL;
  101. bc_init_num (&int_part);
  102. bc_divide (num, BCG(_one_), &int_part, 0);
  103. bc_init_num (&frac_part);
  104. bc_init_num (&cur_dig);
  105. bc_init_num (&base);
  106. bc_sub (num, int_part, &frac_part, 0);
  107. /* Make the INT_PART and FRAC_PART positive. */
  108. int_part->n_sign = PLUS;
  109. frac_part->n_sign = PLUS;
  110. bc_int2num (&base, o_base);
  111. bc_init_num (&max_o_digit);
  112. bc_int2num (&max_o_digit, o_base-1);
  113. /* Get the digits of the integer part and push them on a stack. */
  114. while (!bc_is_zero (int_part))
  115. {
  116. bc_modulo (int_part, base, &cur_dig, 0);
  117. /* PHP Change: malloc() -> emalloc() */
  118. temp = (stk_rec *) emalloc (sizeof(stk_rec));
  119. temp->digit = bc_num2long (cur_dig);
  120. temp->next = digits;
  121. digits = temp;
  122. bc_divide (int_part, base, &int_part, 0);
  123. }
  124. /* Print the digits on the stack. */
  125. if (digits != NULL)
  126. {
  127. /* Output the digits. */
  128. while (digits != NULL)
  129. {
  130. temp = digits;
  131. digits = digits->next;
  132. if (o_base <= 16)
  133. (*out_char) (ref_str[ (int) temp->digit]);
  134. else
  135. bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char);
  136. efree (temp);
  137. }
  138. }
  139. /* Get and print the digits of the fraction part. */
  140. if (num->n_scale > 0)
  141. {
  142. (*out_char) ('.');
  143. pre_space = false;
  144. t_num = bc_copy_num (BCG(_one_));
  145. while (t_num->n_len <= num->n_scale) {
  146. bc_multiply (frac_part, base, &frac_part, num->n_scale);
  147. fdigit = bc_num2long (frac_part);
  148. bc_int2num (&int_part, fdigit);
  149. bc_sub (frac_part, int_part, &frac_part, 0);
  150. if (o_base <= 16)
  151. (*out_char) (ref_str[fdigit]);
  152. else {
  153. bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char);
  154. pre_space = true;
  155. }
  156. bc_multiply (t_num, base, &t_num, 0);
  157. }
  158. bc_free_num (&t_num);
  159. }
  160. /* Clean up. */
  161. bc_free_num (&int_part);
  162. bc_free_num (&frac_part);
  163. bc_free_num (&base);
  164. bc_free_num (&cur_dig);
  165. bc_free_num (&max_o_digit);
  166. }
  167. }