예제 #1
0
static bool printchar( char chr, struct _PDCLIB_status_t * status )
{
    if( ! ( status->flags & E_minus ) )
    {
        // Right justification
        if ( status-> width ) {
            size_t justification = status->width - status->current - 1;
            if ( !cbrept( status, ' ', justification ))
                return false;
        }

        if ( !cbout( status, &chr, 1 ))
            return false;
    } else {
        // Left justification

        if ( !cbout( status, &chr, 1 ))
            return false;

        if ( status->width > status->current ) {
            if ( !cbrept( status, ' ', status->width - status->current ) )
                return false;
        }
    }

    return true;
}
예제 #2
0
파일: _vcbprintf.c 프로젝트: kubasz/NovuOS
int _vcbprintf(
    void *p,
    size_t ( *cb ) ( void *p, const char *buf, size_t size ),
    const char *format,
    va_list arg )
{
    struct _PDCLIB_status_t status;
    status.base     = 0;
    status.flags    = 0;
    status.n        = 0;
    status.i        = 0;
    status.current  = 0;
    status.width    = 0;
    status.prec     = 0;
    status.ctx      = p;
    status.write    = cb;
    va_copy( status.arg, arg );

    /* Alternate between outputing runs of verbatim text and conversions */
    while ( *format != '\0' )
    {
        const char *mark = format;
        while ( *format != '\0' && *format != '%')
        {
            format++;
        }

        if ( mark != format )
        {
            if ( !cbout(&status, mark, format - mark) )
                return -1;
        }

        if ( *format == '%' ) {
            int consumed = _PDCLIB_print( format, &status );
            if ( consumed > 0 )
            {
                format += consumed;
            }
            else if ( consumed == 0 )
            {
                /* not a conversion specifier, print verbatim */
                if ( !cbout(&status, format++, 1) )
                    return -1;
            }
            else
            {
                /* I/O callback error */
                return -1;
            }
        }
    }

    va_end( status.arg );
    return status.i;
}
예제 #3
0
/* repeated output of a single character */
static inline bool cbrept(
    struct _PDCLIB_status_t * status,
    char c,
    size_t times )
{
    if ( sizeof(size_t) == 8 && CHAR_BIT == 8)
    {
        uint64_t spread = UINT64_C(0x0101010101010101) * c;
        while ( times )
        {
            size_t n = times > 8 ? 8 : times;
            if ( !cbout( status, &spread, n ) )
                return false;
            times -= n;
        }
        return true;
    }
    else if ( sizeof(size_t) == 4  && CHAR_BIT == 8)
    {
        uint32_t spread = UINT32_C(0x01010101) * c;
        while ( times )
        {
            size_t n = times > 4 ? 4 : times;
            if ( !cbout( status, &spread, n ) )
                return false;
            times -= n;
        }
        return true;
    }
    else
    {
        while ( times )
        {
            if ( !cbout( status, &c, 1) )
                return false;
            times--;
        }
        return true;
    }
}
예제 #4
0
/* print a string. returns false if an I/O error occured */
static bool printstr( const char * str, struct _PDCLIB_status_t * status )
{
    size_t len = status->prec >= 0 ? strnlen( str, status-> prec)
                                   : strlen(str);

    if ( status->width == 0 || status->flags & E_minus )
    {
        // Simple case or left justification
        if ( status->prec > 0 )
        {
            len = (unsigned) status->prec < len ? (unsigned)  status->prec : len;
        }

        if ( !cbout( status, str, len ) )
            return false;

        /* right padding */
        if ( status->width > status->current ) {
            len = status->width - status->current;

            if ( !cbrept( status, ' ', len ) )
                return false;
        }
    } else {
        // Right justification

        if ( status->width > len ) {
            size_t padding = status->width - len;

            if ( !cbrept( status, ' ', padding ))
                return false;
        }

        if ( !cbout( status, str, len ) )
            return false;
    }

    return true;
}
예제 #5
0
int _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
{
    const char * orig_spec = spec;
    if ( *(++spec) == '%' )
    {
        /* %% -> print single '%' */
        if ( !cbout(status, spec, 1) )
            return -1;
        ++spec;
        return (spec - orig_spec);
    }
    /* Initializing status structure */
    status->flags = 0;
    status->base  = 0;
    status->current  = 0;
    status->width = 0;
    status->prec  = EOF;

    /* First come 0..n flags */
    do
    {
        switch ( *spec )
        {
            case '-':
                /* left-aligned output */
                status->flags |= E_minus;
                ++spec;
                break;
            case '+':
                /* positive numbers prefixed with '+' */
                status->flags |= E_plus;
                ++spec;
                break;
            case '#':
                /* alternative format (leading 0x for hex, 0 for octal) */
                status->flags |= E_alt;
                ++spec;
                break;
            case ' ':
                /* positive numbers prefixed with ' ' */
                status->flags |= E_space;
                ++spec;
                break;
            case '0':
                /* right-aligned padding done with '0' instead of ' ' */
                status->flags |= E_zero;
                ++spec;
                break;
            default:
                /* not a flag, exit flag parsing */
                status->flags |= E_done;
                break;
        }
    } while ( ! ( status->flags & E_done ) );

    /* Optional field width */
    if ( *spec == '*' )
    {
        /* Retrieve width value from argument stack */
        int width = va_arg( status->arg, int );
        if ( width < 0 )
        {
            status->flags |= E_minus;
            status->width = abs( width );
        }
        else
        {
            status->width = width;
        }
        ++spec;
    }
예제 #6
0
static bool int2base( uintmax_t value, struct _PDCLIB_status_t * status )
{
    char sign = 0;
    if ( ! ( status->flags & E_unsigned ) )
    {
        intmax_t signval = (intmax_t) value;
        bool negative = signval < 0;
        value = signval < 0 ? -signval : signval;

        if ( negative )
        {
            sign = '-';
        }
        else if ( status->flags & E_plus )
        {
            sign = '+';
        }
        else if (status->flags & E_space )
        {
            sign = ' ';
        }
    }

    // The user could theoretically ask for a silly buffer length here.
    // Perhaps after a certain size we should malloc? Or do we refuse to protect
    // them from their own stupidity?
    size_t bufLen = (status->width > maxIntLen ? status->width : maxIntLen) + 2;
    char outbuf[bufLen];
    char * outend = outbuf + bufLen;
    int written = 0;

    // Build up our output string - backwards
    {
        const char * digits = (status->flags & E_lower) ?
                                _PDCLIB_digits : _PDCLIB_Xdigits;
        uintmax_t remaining = value;
        if(status->prec != 0 || remaining != 0) do {
            uintmax_t digit = remaining % status->base;
            remaining /= status->base;

            outend[-++written] = digits[digit];
        } while(remaining != 0);
    }

    // Pad field out to the precision specification
    while( (long) written < status->prec ) outend[-++written] = '0';

    // If a field width specified, and zero padding was requested, then pad to
    // the field width
    unsigned padding = 0;
    if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
    {
        while( written < (int) status->width )
        {
            outend[-++written] = '0';
            padding++;
        }
    }

    // Prefixes
    if ( sign != 0 )
    {
        if ( padding == 0 ) written++;
        outend[-written] = sign;
    }
    else if ( status->flags & E_alt )
    {
        switch ( status->base )
        {
            case 8:
                if ( outend[-written] != '0' ) outend[-++written] = '0';
                break;
            case 16:
                // No prefix if zero
                if ( value == 0 ) break;

                written += padding < 2 ? 2 - padding : 0;
                outend[-written    ] = '0';
                outend[-written + 1] = (status->flags & E_lower) ? 'x' : 'X';
                break;
            default:
                break;
        }
    }

    // Space padding to field width
    if ( ! ( status->flags & ( E_minus | E_zero ) ) )
    {
        while( written < (int) status->width ) outend[-++written] = ' ';
    }

    // Write output
    return cbout( status, outend - written, written );
}