📄 sprint.c
字号:
/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */static char RCSid[] = "sprint.c,v 1.3 1995/09/03 00:36:21 duane Exp" ;#include <string.h>#include <ctype.h>#include "sio.h"#include "impl.h"#ifndef WIDE_INT#define WIDE_INT long#endiftypedef WIDE_INT wide_int ;typedef unsigned WIDE_INT u_wide_int ;typedef int bool_int ;#define S_NULL "(null)"#define S_NULL_LEN 6#define FLOAT_DIGITS 6#define EXPONENT_LENGTH 10/* * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions * * XXX: this is a magic number; do not decrease it */#define NUM_BUF_SIZE 512/* * The INS_CHAR macro inserts a character in the buffer and writes * the buffer back to disk if necessary * It uses the char pointers sp and bep: * sp points to the next available character in the buffer * bep points to the end-of-buffer+1 * While using this macro, note that the nextb pointer is NOT updated. * * No I/O is performed if fd is not positive. Negative fd values imply * conversion with the output directed to a string. Excess characters * are discarded if the string overflows. * * NOTE: Evaluation of the c argument should not have any side-effects */#define INS_CHAR( c, sp, bep, odp, cc, fd ) \ { \ if ( sp < bep ) \ { \ *sp++ = c ; \ cc++ ; \ } \ else \ { \ if ( fd >= 0 ) \ { \ odp->nextb = sp ; \ if ( __sio_writef( odp, fd ) != bep - odp->start ) \ return( ( cc != 0 ) ? cc : SIO_ERR ) ; \ sp = odp->nextb ; \ *sp++ = c ; \ cc++ ; \ } \ } \ if ( __SIO_MUST_FLUSH( *odp, c ) && fd >= 0 ) \ { \ int b_in_buffer = sp - odp->start ; \ \ odp->nextb = sp ; \ if ( __sio_writef( odp, fd ) != b_in_buffer ) \ return( cc ) ; \ sp = odp->nextb ; \ } \ }#define NUM( c ) ( c - '0' )#define STR_TO_DEC( str, num ) \ num = NUM( *str++ ) ; \ while ( isdigit( *str ) ) \ { \ num *= 10 ; \ num += NUM( *str++ ) ; \ }/* * This macro does zero padding so that the precision * requirement is satisfied. The padding is done by * adding '0's to the left of the string that is going * to be printed. */#define FIX_PRECISION( adjust, precision, s, s_len ) \ if ( adjust ) \ while ( s_len < precision ) \ { \ *--s = '0' ; \ s_len++ ; \ }/* * Macro that does padding. The padding is done by printing * the character ch. */#define PAD( width, len, ch ) do \ { \ INS_CHAR( ch, sp, bep, odp, cc, fd ) ; \ width-- ; \ } \ while ( width > len )/* * Prefix the character ch to the string str * Increase length * Set the has_prefix flag */#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YESPRIVATE char *conv_10(), *conv_p2(), *conv_fp() ;/* * Sprint is the equivalent of printf for SIO. * It returns the # of chars written * Assumptions: * - all floating point arguments are passed as doubles *//* VARARGS2 */#ifdef __STRICT_ANSI__int Sprint( int fd, char *fmt, ... ){ __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; register int cc ; va_list ap ; IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; va_start( ap, fmt ) ;#elseint Sprint( fd, fmt, va_alist ) int fd ; register char *fmt ; va_dcl{ __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; register int cc ; va_list ap ; IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; va_start( ap ) ;#endif cc = __sio_converter( odp, fd, fmt, ap ) ; va_end( ap ) ; return( cc ) ;}/* * This is the equivalent of vfprintf for SIO */int Sprintv( fd, fmt, ap ) int fd ; char *fmt ; va_list ap ;{ __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; return( __sio_converter( odp, fd, fmt, ap ) ) ;}/* * Convert a floating point number to a string formats 'f', 'e' or 'E'. * The result is placed in buf, and len denotes the length of the string * The sign is returned in the is_negative argument (and is not placed * in buf). */PRIVATE char *conv_fp( format, num, add_dp, precision, is_negative, buf, len ) register char format ; register double num ; boolean_e add_dp ; /* always add decimal point if YES */ int precision ; bool_int *is_negative ; char buf[] ; int *len ;{ register char *s = buf ; register char *p ; int decimal_point ;# if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__bsdi__) char *ecvt(), *fcvt() ;# endif char *conv_10() ;# if 0 char *strcpy() ;# endif# if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__bsdi__) if ( format == 'f' ) p = fcvt( num, precision, &decimal_point, is_negative ) ; else /* either e or E format */ p = ecvt( num, precision+1, &decimal_point, is_negative ) ;# endif /* * Check for Infinity and NaN */ if ( isalpha( *p ) ) { *len = strlen( strcpy( buf, p ) ) ; *is_negative = FALSE ; return( buf ) ; } if ( format == 'f' ) if ( decimal_point <= 0 ) { *s++ = '0' ; if ( precision > 0 ) { *s++ = '.' ; while ( decimal_point++ < 0 ) *s++ = '0' ; } else if ( add_dp ) *s++ = '.' ; } else { while ( decimal_point-- > 0 ) *s++ = *p++ ; if ( precision > 0 || add_dp ) *s++ = '.' ; } else { *s++ = *p++ ; if ( precision > 0 || add_dp ) *s++ = '.' ; } /* * copy the rest of p, the NUL is NOT copied */ while ( *p ) *s++ = *p++ ; if ( format != 'f' ) { char temp[ EXPONENT_LENGTH ] ; /* for exponent conversion */ int t_len ; bool_int exponent_is_negative ; *s++ = format ; /* either e or E */ decimal_point-- ; if ( decimal_point != 0 ) { p = conv_10( (wide_int)decimal_point, FALSE, &exponent_is_negative, &temp[ EXPONENT_LENGTH ], &t_len ) ; *s++ = exponent_is_negative ? '-' : '+' ; /* * Make sure the exponent has at least 2 digits */ if ( t_len == 1 ) *s++ = '0' ; while ( t_len-- ) *s++ = *p++ ; } else { *s++ = '+' ; *s++ = '0' ; *s++ = '0' ; } } *len = s - buf ; return( buf ) ;}/* * Convert num to a base X number where X is a power of 2. nbits determines X. * For example, if nbits is 3, we do base 8 conversion * Return value: * a pointer to a string containing the number * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */PRIVATE char *conv_p2( num, nbits, format, buf_end, len ) register u_wide_int num ; register int nbits ; char format ; char *buf_end ; register int *len ;{ register int mask = ( 1 << nbits ) - 1 ; register char *p = buf_end ; static char low_digits[] = "0123456789abcdef" ; static char upper_digits[] = "0123456789ABCDEF" ; register char *digits = ( format == 'X' ) ? upper_digits : low_digits ; do { *--p = digits[ num & mask ] ; num >>= nbits ; } while( num ) ; *len = buf_end - p ; return( p ) ;}/* * Convert num to its decimal format. * Return value: * - a pointer to a string containing the number (no sign) * - len contains the length of the string * - is_negative is set to TRUE or FALSE depending on the sign * of the number (always set to FALSE if is_unsigned is TRUE) * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */PRIVATE char *conv_10( num, is_unsigned, is_negative, buf_end, len ) register wide_int num ; register bool_int is_unsigned ; register bool_int *is_negative ; char *buf_end ; register int *len ;{ register char *p = buf_end ; register u_wide_int magnitude ; if ( is_unsigned ) { magnitude = (u_wide_int) num ; *is_negative = FALSE ; } else { *is_negative = ( num < 0 ) ; /* * On a 2's complement machine, negating the most negative integer * results in a number that cannot be represented as a signed integer. * Here is what we do to obtain the number's magnitude: * a. add 1 to the number * b. negate it (becomes positive) * c. convert it to unsigned * d. add 1 */ if ( *is_negative ) { wide_int t = num + 1 ; magnitude = ( (u_wide_int) -t ) + 1 ; } else magnitude = (u_wide_int) num ; } /* * We use a do-while loop so that we write at least 1 digit */ do { register u_wide_int new_magnitude = magnitude / 10 ; *--p = magnitude - new_magnitude*10 + '0' ; magnitude = new_magnitude ; } while ( magnitude ) ; *len = buf_end - p ; return( p ) ;}/* * Do format conversion placing the output in odp */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -