mprintf.c

Go to the documentation of this file.
00001 
00039 #include "mprintf.h"
00040 #define edigito(c) ((c)>='0' && (c)<='9')
00041 
00042 /* uso interno: Escreve o numero de tras para a frente */
00043 int u2str(char *buf, unsigned int num, int base)
00044 {
00045 int nd=0, c;
00046 do      {
00047         c = (num % base) + '0';
00048         if(c > '9') c+=7;
00049         buf[nd++] = c;
00050         num /= base;
00051         } while(num);
00052 return nd;
00053 }
00054 
00055 /* Converte string para numero (similar ao atoi da biblioteca padrao);
00056  Usa-se assim:
00057 char buf[20];   // Para armazenar o texto lido
00058 int i;          // Vai ler o numero i
00059 U0gets(buf,20); // Le como texto
00060 i = atoi(buf);  // Converte para numero
00061 */
00062 int atoi(char *str)
00063 {
00064 int x, d, s;
00065 x=s=0;
00066 while(!edigito(*str)) s |= (*str++ == '-');
00067 do      {
00068         d = *str++;
00069         if(!edigito(d)) break;
00070         x = x*10 + d - '0';
00071         } while(1);
00072 return s? -x: x;
00073 }
00074 
00075 /* Converte string para numero tipo double (com notacao cientifica)*/
00076 double atod(char *str)
00077 {
00078 double x, p;
00079 int d, s;
00080 p=1.0;
00081 x=0.0; s=0;
00082 while(*str == ' ') str++;
00083 if(*str == '-') { s=1; str++; }
00084 do      {
00085         d = *str++;
00086         if(d=='.') { d = *str++; s |= 2; }
00087         if(d < '0' || d > '9') break;
00088         x = x*10 + d - '0';
00089         if(s & 2) p *=10.;
00090         } while(1);
00091 if(d=='e' || d=='E'){
00092         if(*str == '-') { str++; s |= 4; }
00093         if(*str == '+') str++;
00094         d=0;
00095         while(edigito(*str)) d = 10*d + (*str++) - '0';
00096         if(s & 4) while(d--) p *= 10.0;
00097         else while(d--) x *= 10.0;
00098         }
00099 if(s & 1) x = -x;
00100 return x/p;
00101 }
00102 
00103 /**** dprint Escreve double ******
00104 x       Numero double que sera escrito
00105 campo   Espaco de campo total (largura em caracteres)
00106 frac    Numero de digitos depois do ponto
00107 putc    Nome da funcao que escreve caractere 
00108 retorna o numero de caracteres escritos  */
00109 int dprint(double x, int campo, int frac, void (*putc)(int))
00110 {
00111 int dig, k, sinal=0, npr=1;
00112 double ar;
00113 if(x < 0) { sinal=1; x=-x; campo--; }
00114 for(ar=0.5, k=0; k<frac; k++) ar/=10.0;
00115 x += ar;
00116 k=0;
00117 campo -= (frac+1);
00118 while(x >= 1.0) { x/=10.0; k++; campo--; }
00119 if(!k) { k=1; campo--; x/=10.0; }
00120 frac += k;
00121 while(campo-- > 0) { putc(' '); npr++; }
00122 if(sinal) { putc('-'); npr++; }
00123 npr += frac;
00124 while(frac--) {
00125         x *= 10;
00126         dig = x;
00127         x -= dig;
00128         putc(dig+'0');
00129         if(!(--k)) { putc('.'); k=800; }
00130         }
00131 return npr;
00132 }
00133 
00134 int va_printf(void (*putc)(int), const char *formato, va_list va)
00135 {
00136 char buf[16];
00137 char *s, *ps;
00138 int c,  frac, n, sinal, base, nprinted;
00139 int campo,padchar;
00140 double x, y;
00141 s=(char *)formato;
00142 nprinted=campo=0;
00143 while((c=*s++)) {
00144         if(c != '%') { putc(c); nprinted++; continue;} 
00145         c=*s++;
00146         sinal=frac=campo=0;
00147         padchar = ((c=='0')? '0' + 0x100:' ' + 0x100);
00148         if(c=='-') { padchar =' '; c=*s++; }
00149         while(edigito(c)) { campo=10*campo+c-'0'; c=*s++; }
00150         if(c=='.') {
00151                 c=*s++;
00152                 while(edigito(c)) { frac=10*frac+c-'0'; c=*s++; }
00153                 }
00154         while(c=='l' || c=='L' || c=='h') c=*s++;
00155         base=10;
00156         if(c >= 'A' && c <= 'Z') c ^= 0x20;
00157         switch(c){
00158                 case 'o': case 'q': base=8; goto lbl_u;
00159                 case 'x': base=16;
00160                 case 'u':
00161                 lbl_u:
00162                         n = u2str(buf, va_arg(va, unsigned int), base);
00163                 lbl_escrevei:
00164                 nprinted += n;
00165                 campo -= (n+sinal);
00166                 if(campo < 0) campo=0;
00167                 nprinted +=campo;
00168                         if(padchar & 0x100) while(campo--) putc(padchar);
00169                         if(sinal) putc('-');
00170                         while(n--) putc(buf[n]);
00171                         break;
00172                 case 'd': case 'i':
00173                         base=va_arg(va, int);
00174                         if(base < 0) { sinal=1; base=-base; }
00175                         n = u2str(buf, base, 10);
00176                         goto lbl_escrevei;
00177                 case 'c':
00178                         if(campo < 0) campo=0;
00179                         nprinted +=campo;
00180                         if(padchar & 0x100) while(campo--) putc(padchar);
00181                         putc(va_arg(va, int)); nprinted++; break;
00182                 case 's':
00183                         ps = va_arg(va, char *);
00184                         for(n=0; ps[n]; n++);
00185                         nprinted += n;
00186                         campo -= n;
00187                         if(campo < 0) campo=0;
00188                         nprinted +=campo;
00189                         if(padchar & 0x100) while(campo--) putc(padchar);
00190                         while(*ps) { putc(*ps); ps++; }
00191                         break;
00192                 case 'e': case 'f': case 'g':
00193                         n=0;
00194                         x=y=va_arg(va, double);
00195                         if(x<0) { x=-x; sinal=1; }
00196                         while((x > 1.0)) { x /= 10.0; n++; }
00197                         if(x) while((x < 1.0)) { x *= 10.0; n--; }
00198                         if(c=='e' || ((c=='g') && 
00199                                 ((n > 9) || ((-n >= frac)&& frac)))){
00200                                 y = (sinal ? -x: x);
00201                                 sinal = 2;
00202                                 campo -=4;
00203                                 if(frac<2) frac=2;
00204                                 }
00205                         c = dprint(y, (padchar & 0x100)?campo:0, frac, putc);
00206                         campo -=c;
00207                         nprinted +=c;
00208                         if(sinal & 2){
00209                                 putc('E');
00210                                 if(n < 0) { putc('-'); n=-n; }
00211                                 else putc('+');
00212                                 if(n>99) { putc((n/100) + '0'); n %= 100; }
00213                                 putc((n / 10) + '0');
00214                                 putc((n % 10) + '0');
00215                                 }
00216                         break;
00217                 case '%': putc(c); nprinted++; break;
00218                 }
00219         if(campo < 0) campo=0;
00220         nprinted +=campo;
00221         if(!(padchar & 0x100)) while(campo--) putc(padchar);
00222         }
00223 return nprinted;
00224 }
00225 
00226 int mprintf(void (*putc)(int), const char *formato, ... )
00227 {
00228 va_list va;
00229 va_start(va,formato);
00230 return va_printf(putc, formato, va);
00231 }
00232 
00233 char *gp_buf;
00234 void sputchar(int c) { *gp_buf++=c; }
00235 
00236 /* Atendendo a pedidos, o meu sprintf: */
00237 int sprintf(char *buf, const char *formato, ... )
00238 {
00239 va_list va;
00240 int n;
00241 va_start(va,formato);
00242 gp_buf=buf;
00243 n=va_printf(sputchar, formato, va);
00244 *gp_buf='\0';
00245 return n;
00246 }