📄 frmwri.c
字号:
/* - FRMWRI.C -
Basic "printf", "sprintf" and "fprintf" formatter.
This module is 100% reentrant and can be adapted to user-defined routines
that needs formatters with special properties like different output chann-
els or new format specifiers.
To reduce size in applications not using real numbers or long integers
the formatter may be compiled to exclude certain parts. This is
controlled by giving a -D option a compilation time.
-DFLOAT_SUPPORT Full ANSI formatter
-DNO_FLOATS Full ANSI except floats
-DREDUCED_SUPPORT Reduced 'int' type of converter
The reduced version of formatter is suitable when program size is critical
rather than formatting power. This routine uses less than 20 bytes of
stack space which makes it practical even in systems with less than 256
bytes of user RAM.
The only formatting specifiers supported by the reduced formatter are:
%% %c %s %d %o %x %X and %hd %ho %hx %hX %ld %lo %lx %lX.
It means that real variables are not supported as well as field
width and precision arguments.
The last eight (h and l modifiers) can easily be removed by
removing the line "#define MODIFIERS_IN_REDUCED".
$Revision: 1.6 $
Copyright 1986 - 1999 IAR Systems. All rights reserved.
*/
#ifndef FLOAT_SUPPORT
#ifndef NO_FLOATS
#ifndef REDUCED_SUPPORT
#error -DFLOAT_SUPPORT, -DNO_FLOATS or -DREDUCED_SUPPORT missing
#endif
#endif
#endif
/* Make it easy for customers to disable h and l
modifiers in REDUCED_SUPPORT by removing the next #define */
#define MODIFIERS_IN_REDUCED
#include "stdarg.h"
#include "float.h"
#include "icclbutl.h" /* Low-level declarations */
#include "sysmac.h"
#ifndef FRMWRI_BUFSIZE
#define FRMWRI_BUFSIZE 134
#endif
#ifndef MEM_ATTRIBUTE
#define MEM_ATTRIBUTE
#endif
#ifdef MODIFIERS_IN_REDUCED
#define IS_SHORT (h_modifier || (sizeof(int) == 2 && !l_modifier))
#else
#define IS_SHORT (sizeof(int) == 2)
#endif
#ifdef FLOAT_SUPPORT
static char *float_conversion(MEM_ATTRIBUTE long double value,
MEM_ATTRIBUTE short nr_of_digits,
MEM_ATTRIBUTE char *buf,
MEM_ATTRIBUTE char format_flag,
MEM_ATTRIBUTE char g_flag,
MEM_ATTRIBUTE char alternate_flag)
{
MEM_ATTRIBUTE char *cp, *buf_pointer;
MEM_ATTRIBUTE short n, i, dec_point_pos, integral_10_log;
buf_pointer = buf;
integral_10_log = 0;
#ifdef _CLIB_FP_INF_NAN
if (value == 0.Infinity)
{
*buf_pointer++ = 'i';
*buf_pointer++ = 'n';
*buf_pointer++ = 'f';
return buf_pointer;
}
else if (value != value)
{
*buf_pointer++ = 'n';
*buf_pointer++ = 'a';
*buf_pointer++ = 'n';
return buf_pointer;
}
#endif
if (value >= 1)
{
while (value >= 1e11) /* To speed up things a bit */
{
value /= 1e10;
integral_10_log += 10;
}
while (value >= 10)
{
value /= 10;
integral_10_log++;
}
}
else if (value) /* Not just 0.0 */
{
while (value <= 1e-10) /* To speed up things a bit */
{
value *= 1e10;
integral_10_log -= 10;
}
while (value < 1)
{
value *= 10;
integral_10_log--;
}
}
if (g_flag)
{
if (integral_10_log < nr_of_digits && integral_10_log >= -4)
{
format_flag = 0;
nr_of_digits -= integral_10_log;
}
nr_of_digits--;
if (alternate_flag)
{
g_flag = 0; /* %#G - No removal of trailing zeros */
}
else
{
alternate_flag = 1; /* %G - Removal of trailing zeros */
}
}
if (format_flag) /* %e or %E */
{
dec_point_pos = 0;
}
else
{
if (integral_10_log < 0) /* Less than one.... */
{
*buf_pointer++ = '0';
if ((n = nr_of_digits) || alternate_flag)
{
*buf_pointer++ = '.';
}
i = 0;
while (--i > integral_10_log && nr_of_digits)
{
*buf_pointer++ = '0';
nr_of_digits--;
}
if (integral_10_log < (-n - 1))
{
goto CLEAN_UP; /* Nothing more to do */
}
dec_point_pos = 1;
}
else
{
dec_point_pos = - integral_10_log;
}
}
i = dec_point_pos;
while (i <= nr_of_digits )
{
value -= n = value; /* n=Digit value=Remainder */
value *= 10; /* Prepare for next shot */
*buf_pointer++ = n + '0';
if ( ! i++ && (nr_of_digits || alternate_flag))
{
*buf_pointer++ = '.';
}
}
if (value >= 5) /* Rounding possible */
{
n = 1; /* Carry */
cp = buf_pointer - 1;
do
{
if (*cp != '.')
if ( (*cp += n) == ('9' + 1) )
{
*cp = '0';
n = 1;
}
else
{
n = 0;
}
} while (cp-- > buf);
if (n)
{
if (format_flag) /* %e or %E */
{
cp = buf_pointer;
while (cp > buf)
{
if (*(cp - 1) == '.')
{
*cp = *(cp - 2);
cp--;
}
else
{
*cp = *(cp - 1);
}
cp--;
}
integral_10_log++;
}
else
{
cp = ++buf_pointer;
while (cp > buf)
{
*cp = *(cp - 1);
cp--;
}
}
*buf = '1';
}
}
CLEAN_UP:
if (g_flag) /* %G - Remove trailing zeros */
{
while (*(buf_pointer - 1) == '0')
{
buf_pointer--;
}
if (*(buf_pointer - 1) == '.')
{
buf_pointer--;
}
}
if (format_flag) /* %e or %E */
{
*buf_pointer++ = format_flag;
if (integral_10_log < 0)
{
*buf_pointer++ = '-';
integral_10_log = -integral_10_log;
}
else
{
*buf_pointer++ = '+';
}
n = 0;
buf_pointer +=10;
do
{
n++;
*buf_pointer++ = (integral_10_log % 10) + '0';
integral_10_log /= 10;
} while ( integral_10_log || n < 2 );
for ( i = n ; n > 0 ; n-- )
*(buf_pointer - 11 - i + n) = *(buf_pointer - n);
buf_pointer -= 10;
}
return buf_pointer;
}
#endif
/*----------------------------------------------------------------------*/
/* */
/* - _formatted_write - */
/* */
/* This routine forms the core and entry of the formatter. The con- */
/* version performed conforms to the ANSI specification for "printf". */
/*----------------------------------------------------------------------*/
int _formatted_write(const char *format,
void put_one_char(char, void *),
void *secret_pointer,
va_list ap)
#ifndef REDUCED_SUPPORT
{
MEM_ATTRIBUTE char format_flag;
MEM_ATTRIBUTE int precision;
MEM_ATTRIBUTE int n;
MEM_ATTRIBUTE int field_width, nr_of_chars;
MEM_ATTRIBUTE char plus_space_flag, left_adjust, l_L_modifier;
MEM_ATTRIBUTE char h_modifier, alternate_flag;
MEM_ATTRIBUTE char nonzero_value;
MEM_ATTRIBUTE unsigned long ulong, div_factor;
#ifdef FLOAT_SUPPORT
MEM_ATTRIBUTE long double fvalue;
#endif
MEM_ATTRIBUTE char *buf_pointer;
MEM_ATTRIBUTE char *ptr, *hex;
MEM_ATTRIBUTE char zeropad;
MEM_ATTRIBUTE char buf[FRMWRI_BUFSIZE];
nr_of_chars = 0;
for (;;) /* Until full format string read */
{
while ((format_flag = *format++) != '%') /* Until '%' or '\0' */
{
if (!format_flag)
return nr_of_chars;
put_one_char(format_flag, secret_pointer);
nr_of_chars++;
}
if (*format == '%') /* %% prints as % */
{
format++;
put_one_char('%',secret_pointer);
nr_of_chars++;
continue;
}
plus_space_flag = left_adjust = alternate_flag = zeropad = 0;
ptr = buf_pointer = &buf[0];
hex = "0123456789ABCDEF";
/*===================================================*/
/* check for leading '-', '+', ' ','#' or '0' flags */
/*===================================================*/
for (;;)
{
switch (*format)
{
case ' ':
if (plus_space_flag)
goto NEXT_FLAG;
case '+':
plus_space_flag = *format;
goto NEXT_FLAG;
case '-':
left_adjust++;
goto NEXT_FLAG;
case '#':
alternate_flag++;
goto NEXT_FLAG;
case '0':
zeropad++;
goto NEXT_FLAG;
}
break;
NEXT_FLAG:
format++;
}
/*===================================*/
/* Optional field width (may be '*') */
/*===================================*/
if (*format == '*')
{
field_width = va_arg(ap, int);
if (field_width < 0)
{
field_width = -field_width;
left_adjust++;
}
format++;
}
else
{
field_width = 0;
while (*format >= '0' && *format <= '9')
field_width = field_width * 10 + (*format++ - '0');
}
if (left_adjust)
zeropad = 0;
/*=============================*/
/* Optional precision (or '*') */
/*=============================*/
if (*format=='.')
{
if (*++format == '*')
{
precision = va_arg(ap, int);
format++;
}
else
{
precision = 0;
while (*format >= '0' && *format <= '9')
precision = precision * 10 + (*format++ - '0');
}
}
else
precision = -1;
/*======================================================*/
/* At this point, "left_adjust" is nonzero if there was */
/* a sign, "zeropad" is 1 if there was a leading zero */
/* and 0 otherwise, "field_width" and "precision" */
/* contain numbers corresponding to the digit strings */
/* before and after the decimal point, respectively, */
/* and "plus_space_flag" is either 0 (no flag) or con- */
/* tains a plus or space character. If there was no */
/* decimal point, "precision" will be -1. */
/*======================================================*/
l_L_modifier = h_modifier = 0;
/*==================================*/
/* Optional 'l','L' r 'h' modifier? */
/*==================================*/
switch (*format)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -