root/ext/bcmath/libbcmath/src/output.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bc_out_long
  2. bc_out_num

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

/* [<][>][^][v][top][bottom][index][help] */