Subversion Repositories shark

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* Project:     OSLib
 * Description: The OS Construction Kit
 * Date:                1.6.2000
 * Idea by:             Luca Abeni & Gerardo Lamastra
 *
 * OSLib is an SO project aimed at developing a common, easy-to-use
 * low-level infrastructure for developing OS kernels and Embedded
 * Applications; it partially derives from the HARTIK project but it
 * currently is independently developed.
 *
 * OSLib is distributed under GPL License, and some of its code has
 * been derived from the Linux kernel source; also some important
 * ideas come from studying the DJGPP go32 extender.
 *
 * We acknowledge the Linux Community, Free Software Foundation,
 * D.J. Delorie and all the other developers who believe in the
 * freedom of software and ideas.
 *
 * For legalese, check out the included GPL license.
 */


#include <ll/i386/stdlib.h>
#include <ll/i386/string.h>
#include <ll/i386/limits.h>
#include <ll/i386/float.h>
#include <ll/i386/mem.h>
#include <ll/stdarg.h>
#include <ll/ctype.h>
#include <ll/math.h>
#include "sprintf.h"

FILE(sprintf);

#define STD_SIZE        0
#define SHORT_SIZE      1
#define LONG_SIZE       2

int vsprintf(char *buf,char *fmt,va_list parms)
{
    int scanned = 0,w = 0,prec = 0,l = 0,size = 0;
    int n1 = 0;
    unsigned n2 = 0,parsing = 0,flag = 0;
    double n3 = 0.0;
    char *base = buf;
    char *sp = NULL;
    void *fp = NULL;
    while (*fmt != 0) {
        if (*fmt != '%' && !parsing) {
            /* No token detected */
            *buf++ = *fmt++;
            scanned++;
        }
        else {     
            /* We need to make a conversion */
            if (*fmt == '%') {
                fmt++;
                parsing = 1;
                w = 10;
                prec = 4;
                size = STD_SIZE;
                flag = 0;
            }
            /* Parse token */
            switch(*fmt) {
                case '%' : *buf++ = '%';
                           scanned++;
                           parsing = 0;
                           break;
                case 'c' : *buf++ = va_arg(parms, char);
                           scanned++;
                           parsing = 0;
                           break;
                case 'i' :
                case 'd' : switch (size) {
                                case STD_SIZE : n1 = va_arg(parms, int);
                                                break;
                                case LONG_SIZE : n1 = va_arg(parms, long int);
                                                 break;
                                case SHORT_SIZE : n1 = va_arg(parms, short int);
                                                  break;
                           }
                           l = dcvt(n1,buf,10,w,flag);
                           scanned += l;
                           buf += l;
                           parsing = 0;
                           break;
                case 'u' : switch (size) {
                                case STD_SIZE : n2 = va_arg(parms, unsigned);
                                                break;
                                case LONG_SIZE : n2 = va_arg(parms, unsigned long);
                                                 break;
                                case SHORT_SIZE : n2 = va_arg(parms, unsigned short);
                                                  break;
                           }
                           l = ucvt(n2,buf,10,w,flag);
                           scanned += l;
                           buf += l;
                           parsing = 0;
                           break;
                case 'x' : switch (size) {
                                case STD_SIZE : n2 = va_arg(parms, unsigned);
                                                break;
                                case LONG_SIZE : n2 = va_arg(parms, unsigned long);
                                                 break;
                                case SHORT_SIZE : n2 = va_arg(parms, unsigned short);
                                                  break;
                           }
                           l = ucvt(n2,buf,16,w,flag);
                           scanned += l;
                           buf += l;
                           parsing = 0;
                           break;
                case 'p' : fp = va_arg(parms, void *);
                           n2 = (unsigned long)(fp);
                           l = ucvt(n2,buf,16,w,0);
                           scanned += l;
                           buf += l;
                           parsing = 0;
                           break;
                case 's' : sp = va_arg(parms, char *);
                           while (*sp != 0) {
                               *buf++ = *sp++;
                               l++;
                           }
                           scanned += l;
                           parsing = 0;
                           break;
                case 'f' : switch (size) {
                                case STD_SIZE : n3 = va_arg(parms, double);
                                                break;
                                case LONG_SIZE : n3 = va_arg(parms, double);
                                                 break;
                                /*
                                It seems that the compilers push a float as
                                a double ... Need to check!
                                */

                                case SHORT_SIZE : n3 = va_arg(parms, double);
                                                  break;
                           }
                           l = fcvt(n3,buf,w,prec,flag);
                           scanned += l;
                           buf += l;
                           parsing = 0;
                           break;
                case 'e' : switch (size) {
                                case STD_SIZE : n3 = va_arg(parms, double);
                                                break;
                                case LONG_SIZE : n3 = va_arg(parms, double);
                                                 break;
                                /*
                                It seems that the compilers push a float as
                                a double ... Need to check!
                                */

                                case SHORT_SIZE : n3 = va_arg(parms, double);
                                                  break;
                           }
                           l = ecvt(n3,buf,w,prec,flag);
                           scanned += l;
                           buf += l;
                           parsing = 0;
                           break;                          
                case 'g' : switch (size) {
                                case STD_SIZE : n3 = va_arg(parms, double);
                                                break;
                                case LONG_SIZE : n3 = va_arg(parms, double);
                                                 break;
                                /*
                                It seems that the compilers push a float as
                                a double ... Need to check!
                                */

                                case SHORT_SIZE : n3 = va_arg(parms, double);
                                                  break;
                           }
                           l = gcvt(n3,buf,w,prec,flag);
                           scanned += l;
                           buf += l;
                           parsing = 0;
                           break;
                case 'l' : size = LONG_SIZE;
                           break;
                case 'n' :
                case 'h' : size = SHORT_SIZE;
                           break;
                case '+' : flag |= ADD_PLUS;
                           break;
                case '-' : flag |= LEFT_PAD;
                           break;
                case '.' : parsing = 2;
                           flag |= RESPECT_WIDTH;
                           break;
                case '1' :
                case '2' :
                case '3' :
                case '4' :
                case '5' :
                case '6' :
                case '7' :
                case '8' :
                case '9' :
                case '0' : if (parsing == 1) {
                              w = strtou(fmt,10,&base);
                              /* MG */
                              /* if the first numeral is zero a ZERO pad is */
                              /* required */
                              /* but not if LEFT_PAD is set*/
                              if (*fmt!='0'||flag&LEFT_PAD)
                                  flag |= SPACE_PAD ;
                              else
                                  flag |= ZERO_PAD ;
                              fmt = base-1;
                           } else if (parsing == 2) {
                               prec = strtou(fmt,10,&base);
                               fmt = base-1;
                               parsing = 1;
                           }
                           break;
                default :  parsing = 0;
                           break;
            }
            fmt++;
        }
    }
    *buf = 0;
    return(scanned);
}

int sprintf(char *buf,char *fmt,...)
{
    va_list parms;
    int result;
    va_start(parms,fmt);
    result = vsprintf(buf,fmt,parms);
    va_end(parms);
    return(result);
}