📄 _printfi.c
字号:
/*****************************************************************************/
/* _PRINTFI.C v2.54 */
/* Copyright (c) 1995-2004 Texas Instruments Incorporated */
/*****************************************************************************/
/*****************************************************************************/
/* This file contains the main routines that all six variations of the */
/* printf function use. The main function in the file is _printfi, */
/* and the other functions here are called by it. */
/* */
/* FUNCTIONS: */
/* _printfi - Perform the main printf routine */
/* _pproc_fflags - Process the format flags for a conversion */
/* _pproc_fwp - Convert field width and precision into numbers */
/* _pproc_str - Process the string (%s) conversion */
/* _setfield - Performs conversions when the '%' is encountered */
/* _pproc_fge - Process the conversion for f, g, G, e, and E */
/* _pconv_f - Perform the %f conversion */
/* _pconv_e - Perform the %e conversion */
/* _pconv_g - Perform the %g conversion */
/* _fcpy - Copy the fraction part of a float to a string */
/* _ecpy - Copy the "E+xx" part of a float to a string */
/* _mcpy - Copy the whole number part of a float to a string */
/* _pproc_diouxp - Process the conversion for d, i, o, u, x, and p */
/* _getarg_diouxp - Get the argument for d, i, o, u, x, or p conversion */
/* _ltostr - Convert an integer to a string of up to base 16 */
/* _div - Divide two integers */
/* */
/* Note: If NOFLOAT is defined at compile time, this file will be compiled */
/* without floating point support. */
/*****************************************************************************/
/*
* 07/30/04 re-entrance of sprintf.
* Change originally came from RTS1.22e modified on 02/27/01 re-entrance of sprintf.
* _ARSIZE is the size of the fld array defined in local static in _setfied
* in the original version of rts.src. Now this array is not static and is
* defined in _printfi because the current stack may be corrupted if the fld
* array is defined in _setfield. The size of the array is reduced to avoid
* to use too much space in stack. The prototype of _setfield is modified to
* use the fld array defined in _printfi.
* The call to malloc in _pproc_str is removed and replaced with a local
* array because malloc uses a global variable.
*/
#include <stdio.h>
#include <format.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <_lock.h>
#define SIGNED_CONV (pfield->conv != 'u' && pfield->conv != 'o' && \
pfield->conv != 'x' && pfield->conv != 'X')
extern _CODE_ACCESS char *fcvt(long double value, register int ndigit,
int *decpt, int *sign);
extern _CODE_ACCESS char *ecvt(long double value, register int ndigit,
int *decpt, int *sign);
extern _CODE_ACCESS char *memccpy(char *dest, const char *src, int ch,
int count);
extern int _printfi(char **_format, va_list _ap, void *_op,
int (*_outc)(char, void *), int (*_outs)(char *, void *));
static void _pproc_fflags(_PFIELD *pfield, char **it);
static void _pproc_fwp(_PFIELD *pfield, char **it, va_list *_ap);
static void _pproc_str(_PFIELD *pfield, void *_op, va_list *_ap, int *count,
int (*_outs)(char *, void *));
static void _setfield(char *fld, _PFIELD *pfield, va_list *_ap);
static void _pproc_fge(_PFIELD *pfield, int *minus_flag, char **a_it,
va_list *_ap);
static void _pconv_f(long double cvt, _PFIELD *pfield, char **a_it);
static void _pconv_e(long double cvt, _PFIELD *pfield, char **a_it);
static void _pconv_g(long double cvt, _PFIELD *pfield, char **a_it);
static char *_fcpy(const char *tmpbuf, int dpt, int trail, int precision,
char **a_it);
static char *_ecpy(int exp, char letter, char **a_it);
static char *_mcpy(const char *tmpbuf, int dpt, int putdec, char **a_it);
static int _pproc_diouxp(_PFIELD *pfield, int *minus_flag, char **a_it,
va_list *_ap);
static uintmax_t _getarg_diouxp(_PFIELD *pfield, va_list *_ap);
static int _ltostr(uintmax_t cvt, int base, char conv, char **a_it);
static uintmax_t _div(uintmax_t cvt, int base);
/*****************************************************************************/
/* _PRINTFI - Perform the main printf routine */
/* */
/* This function processes the format string. It copies the format */
/* string into the result string until a '%' is encountered, where any */
/* flags, the field width, the precision, and the type of conversion are */
/* read in, stored in a structure called PFIELD, and passed to _SETFIELD, */
/* where the actual conversion is processed. This function returns */
/* the number of characters output. */
/* */
/*****************************************************************************/
int _printfi(char **_format, va_list _ap, void *_op,
int (*_outc)(char, void *), int (*_outs)(char *, void *))
{
/*------------------------------------------------------------------------*/
/* Local Variables */
/* */
/* *end - A pointer to the end of the format string */
/* *pfield - A pointer to a structure _PFIELD, which stores all of */
/* flags and parameters needed to perform a conversion. */
/*------------------------------------------------------------------------*/
char *end = *_format + strlen(*_format);
int count = 0;
_PFIELD pfield;
char fld[_ARSIZE];
/*------------------------------------------------------------------------*/
/* Iterate through the format string until the end of it is reached. */
/*------------------------------------------------------------------------*/
while(*_format < end)
{
/*---------------------------------------------------------------------*/
/* Initialize PFIELD. */
/*---------------------------------------------------------------------*/
pfield.flags = 0;
pfield.fwidth = 0;
pfield.precision = -1;
pfield.conv = 0;
/*---------------------------------------------------------------------*/
/* Copy the format string directly to the target string until a '%' */
/* is encountered. */
/*---------------------------------------------------------------------*/
for(; **_format != '%' && **_format != '\0';
_outc(*((*_format)++), _op), count++);
/*---------------------------------------------------------------------*/
/* If the end of the format string has been reached, break out of the */
/* while loop. */
/*---------------------------------------------------------------------*/
if(! (**_format)) break;
(*_format)++; /* Skip to the character after the '%' */
/*---------------------------------------------------------------------*/
/* Process the flags immediately after the '%'. */
/*---------------------------------------------------------------------*/
_pproc_fflags(&pfield, _format);
/*---------------------------------------------------------------------*/
/* Convert the field width and precision into numbers. */
/*---------------------------------------------------------------------*/
_pproc_fwp(&pfield, _format, &_ap);
/*---------------------------------------------------------------------*/
/* If the h, l, or L flag was specified, set the corresponding flag */
/* in pfield. */
/*---------------------------------------------------------------------*/
switch (**_format)
{
case 'L': _SET(&pfield, _MFLD); (*_format)++; break;
case 'h': _SET(&pfield, _MFH); (*_format)++; break;
case 'l':
{
(*_format)++;
if (**_format == 'l') { _SET(&pfield, _MFLL); (*_format)++; }
else _SET(&pfield, _MFL);
}
}
/*---------------------------------------------------------------------*/
/* Set the conversion character in pfield. */
/*---------------------------------------------------------------------*/
pfield.conv = *((*_format)++);
/*---------------------------------------------------------------------*/
/* If 'n' is the conversion specifier, process it in this function, */
/* since it is the only one that makes no conversions. It just stores */
/* the number of characters printed so far into the next argument. */
/* Otherwise, call _SETFIELD which performs the conversion. */
/*---------------------------------------------------------------------*/
if(pfield.conv == 'n')
switch (pfield.flags & (_MFLL | _MFL | _MFH))
{
#ifdef LLONG_MAX
/* The 'll' flag was specified */
case _MFLL : *(va_arg(_ap, long long*)) = (long long)count;
break;
#endif
/* The 'l' flag was specified */
case _MFL : *(va_arg(_ap, long*)) = (long)count;
break;
/* The 'h' flag was specified */
case _MFH : *(va_arg(_ap, short*)) = (short)count;
break;
default : *(va_arg(_ap, int*)) = (int)count;
break;
}
else if(pfield.conv == 's')
_pproc_str(&pfield, _op, &_ap, &count, _outs);
else
{
/*------------------------------------------------------------------*/
/* Append the converted string to the result string, and reposition */
/* its iterator, it2. */
/*------------------------------------------------------------------*/
/* Must hold the system lock to call _setfield() because it returns
a static buffer. */
_lock();
_setfield(fld, &pfield, &_ap);
count += _outs(fld, _op);
_unlock();
}
}
return (count);
}
/*****************************************************************************/
/* _PPROC_FFLAGS - Process the format flags for a conversion */
/* */
/* This function takes the flags directly after the '%' and stores them */
/* in the _PFIELD structure PFIELD for later reference. */
/* */
/*****************************************************************************/
static void _pproc_fflags(_PFIELD *pfield, char **it)
{
/*------------------------------------------------------------------------*/
/* Local variables */
/*------------------------------------------------------------------------*/
int flags_done = 0;
/*---------------------------------------------------------------------*/
/* Read in all of the flags associated with this conversion, and set */
/* the corresponding flags in the PFIELD structure. */
/*---------------------------------------------------------------------*/
while(! flags_done)
switch (**it)
{
case '-' : _SET(pfield, _PFMINUS);
(*it)++;
break;
case '+' : _SET(pfield, _PFPLUS);
(*it)++;
break;
case ' ' : _SET(pfield, _PFSPACE);
(*it)++;
break;
case '#' : _SET(pfield, _PFPOUND);
(*it)++;
break;
case '0' : _SET(pfield, _PFZERO);
(*it)++;
break;
default : flags_done = 1;
}
return;
}
/*****************************************************************************/
/* _PPROC_FWP - Convert the field width and precision from the format */
/* string into numbers. */
/* */
/* This function reads the field and precision out of the format string */
/* and converts them into numbers that will be stored in the _PFIELD */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -