Subversion Repositories filter_foundry

Rev

Rev 193 | Rev 268 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.         This file is part of a common library
  3.     Copyright (C) 2002-6 Toby Thain, toby@telegraphics.com.au
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by  
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License  
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19.  
  20. #include <stdarg.h>
  21. #include <string.h> // memcpy
  22.  
  23. #include "sprintf_tiny.h"
  24. #include "str.h"
  25.  
  26. // integer exponentiation;
  27. // may not be more efficient than repeated multiplication, for small n
  28. // (a small lookup table would be much quicker!)
  29. // refer: http://www-mitpress.mit.edu/sicp/chapter1/node15.html
  30. // and http://www.uvsc.edu/profpages/merrinst/exponentiation_and_java.html
  31. long int_exp(long b,int n){
  32.         long temp;
  33.         if(n&1)
  34.                 return b*int_exp(b,n^1);
  35.         else
  36.                 return n ? ( temp = int_exp(b,n>>1),temp*temp ) : 1;
  37. }
  38.  
  39. // format a signed integer as a decimal string
  40. // returns pointer after last character copied
  41. // (easily generalised to other bases)
  42. // *** this is reimplemented here mainly to avoid
  43. // *** global data, a dealbreaker on MPW 68K
  44.  
  45. #define INT_BASE 10
  46.  
  47. // format a positive integer; return pointer after last digit
  48. // DON'T add trailing NUL
  49. char *udigits(char *p,unsigned long x,int base){
  50.         long m = x/base;
  51.         if(m)
  52.                 p = udigits(p,m,base);
  53.         *p++ = (x%base)+'0';
  54.         return p;
  55. }
  56. // format a possibly negative integer;
  57. // return pointer to trailing NUL (after last digit)
  58. char *int_str(char *dst,long x,int base){
  59.         char *p = dst;
  60.         if(x<0){ // handle negative case
  61.                 *p++ = '-';
  62.                 x = -x;
  63.         }
  64.         p = udigits(p,x,base);
  65.         *p = 0; // add terminating null
  66.         return p;
  67. }      
  68.  
  69. // format unsigned integer into n decimal places, zero padded
  70. // return pointer to trailing NUL (after last digit)
  71. char *int_strpad(char *dst,unsigned long x,int places,int base){
  72.         char *p;
  73.         // generate digits, storing last to first
  74.         for(p=dst+places;p!=dst;x/=base)
  75.                 *(--p) = (x%base)+'0';
  76.         dst[places] = 0; // add terminating null
  77.         return dst+places;
  78. }
  79.  
  80. // quick and dirty way to format a double value as a string
  81. // with a certain number of decimal places
  82. // note INT_BASE^decplaces must be representable as signed long
  83. // therefore WILL FAIL FOR (base 10) decplaces > 9 !!
  84. // will also fail for fp values > 2^31-1
  85. char *float_str(char *dst,double x,int places){
  86.         char *q = dst;
  87.  
  88.         // format integer part
  89.         q = int_str(q,(long)x /*truncated towards zero*/,INT_BASE);
  90.         *q++ = '.';
  91.        
  92.         // format fractional part
  93.         return int_strpad(q,(x-(long)x)*int_exp(INT_BASE,places)+.5,places,INT_BASE);
  94. }
  95.  
  96. // *** this is here because the stdio sprintf()
  97. // *** has global data, which breaks a 68K code resource build.
  98. // *** (also, sprintf() brings a lot of unnecessary baggage)
  99.  
  100. int vsprintf_tiny(char *s,char *fmt,va_list v){
  101.         char *p,*q;
  102.        
  103.         for(p=fmt,q=s;*p;)
  104.                 if(*p == '%'){
  105.                         int lflag = 0;
  106.                         ++p; // eat '%'
  107.                         if(*p == 'l'){
  108.                                 lflag = 1;
  109.                                 ++p; // eat 'l'
  110.                         }
  111.                         switch(*p){
  112.                         case 'c': *q++ = va_arg(v,int); break;
  113. //                      case 'o': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),8); break;
  114.                         case 'i':
  115.                         case 'd': q = int_str(q,lflag ? va_arg(v,long) : va_arg(v,int),10); break;
  116.                         case 'u': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),10); break;
  117. //                      case 'x': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),16); break;
  118.                         case 'F': q = float_str(q,va_arg(v,double),1); break;
  119.                         case 'g':
  120.                         case 'f': q = float_str(q,va_arg(v,double),4); break;
  121.                         case 's': q = cat(q,va_arg(v,char*)); break;
  122.                         default: *q++ = *p;
  123.                         }
  124.                         ++p; // eat format character
  125.                 }else
  126.                         *q++ = *p++;
  127.  
  128.         *q = 0;
  129.         return q - s;
  130. }
  131.  
  132. int sprintf_tiny(char *s,char *fmt,...){
  133.         va_list v;
  134.         int n;
  135.        
  136.         va_start(v,fmt);
  137.         n = vsprintf_tiny(s,fmt,v);
  138.         va_end(v);
  139.         return n;
  140. }
  141.