mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
242 lines
6.5 KiB
C
242 lines
6.5 KiB
C
/* $Id: log-prf.c,v 1.4 2009/08/30 16:56:42 fredette Exp $ */
|
|
|
|
/* libtme/log-prf.c - a printf function body: */
|
|
|
|
/*
|
|
* Copyright (c) 2003 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
{
|
|
|
|
/* start the variable arguments: */
|
|
#ifdef HAVE_STDARG_H
|
|
va_start(prf_args, prf_format);
|
|
#else /* HAVE_STDARG_H */
|
|
va_start(prf_args);
|
|
#endif /* HAVE_STDARG_H */
|
|
|
|
/* we are in state zero and our aggregate begins at the
|
|
beginning of the format: */
|
|
prf_state = 0;
|
|
prf_agg = prf_format;
|
|
|
|
/* to silence gcc -Wuninitialized: */
|
|
prf_flag_ls = (const char *) NULL;
|
|
prf_flag_0 = FALSE;
|
|
prf_width = -1;
|
|
|
|
/* process format characters until we get to the NUL: */
|
|
for(;;) {
|
|
|
|
/* get the next format character: */
|
|
prf_char = *(prf_format++);
|
|
|
|
/* handle a 'NUL' specially: */
|
|
if (prf_char == '\0') {
|
|
|
|
/* if we were in state zero, dump any aggregate: */
|
|
if (prf_state == 0) {
|
|
if ((prf_format - prf_agg) > 1) {
|
|
PRF_OUT_MEM(prf_agg, (prf_format - prf_agg) - 1);
|
|
}
|
|
}
|
|
|
|
/* we're done: */
|
|
break;
|
|
}
|
|
|
|
/* dispatch on our state: */
|
|
switch (prf_state) {
|
|
|
|
/* state 0: "": */
|
|
case 0:
|
|
|
|
/* on a '%', dump any aggregate and move to state one: */
|
|
if (prf_char == '%') {
|
|
assert(prf_format > prf_agg);
|
|
if ((prf_format - prf_agg) > 1) {
|
|
PRF_OUT_MEM(prf_agg, (prf_format - prf_agg) - 1);
|
|
}
|
|
prf_state = 1;
|
|
}
|
|
|
|
/* otherwise, remain in state zero, and the character gets added
|
|
automatically to the aggregate: */
|
|
else {
|
|
/* nothing */
|
|
}
|
|
break;
|
|
|
|
/* state 1: "%": */
|
|
case 1:
|
|
|
|
/* if this is another '%', print a single '%' and move to state zero: */
|
|
if (prf_char == '%') {
|
|
PRF_OUT_CHAR('%');
|
|
prf_agg = prf_format;
|
|
prf_state = 0;
|
|
break;
|
|
}
|
|
|
|
/* reset all flags, precisions, etc., and enter state two: */
|
|
prf_flag_ls = "ll" + 2;
|
|
prf_flag_0 = FALSE;
|
|
prf_width = -1;
|
|
prf_state = 2;
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
/* state 2: "%" followed by zero or more flags, precisions, etc: */
|
|
case 2:
|
|
|
|
/* dispatch on this character: */
|
|
prf_digit = 9;
|
|
switch (prf_char) {
|
|
|
|
/* the 'l' flag: */
|
|
case 'l': prf_flag_ls -= (prf_flag_ls[0] == '\0' || prf_flag_ls[1] == '\0'); break;
|
|
|
|
/* a width: */
|
|
case '0':
|
|
if (prf_width < 0) {
|
|
prf_flag_0 = TRUE;
|
|
}
|
|
prf_digit--;
|
|
/* FALLTHROUGH */
|
|
case '1': prf_digit--;
|
|
case '2': prf_digit--;
|
|
case '3': prf_digit--;
|
|
case '4': prf_digit--;
|
|
case '5': prf_digit--;
|
|
case '6': prf_digit--;
|
|
case '7': prf_digit--;
|
|
case '8': prf_digit--;
|
|
case '9':
|
|
if (prf_width < 0) {
|
|
prf_width = 0;
|
|
}
|
|
prf_width = (prf_width * 10) + prf_digit;
|
|
break;
|
|
|
|
/* the 'd', 'u', 'x', and 'X' conversions: */
|
|
case 'd':
|
|
case 'u':
|
|
case 'x':
|
|
case 'X':
|
|
if (prf_width < 0) {
|
|
sprintf(prf_format_buffer,
|
|
"%%%s%c",
|
|
prf_flag_ls,
|
|
prf_char);
|
|
prf_width = 0;
|
|
}
|
|
else {
|
|
sprintf(prf_format_buffer,
|
|
"%%%s%d%s%c",
|
|
(prf_flag_0
|
|
? "0"
|
|
: ""),
|
|
prf_width,
|
|
prf_flag_ls,
|
|
prf_char);
|
|
}
|
|
/* NB: we always allocate at least the specified field width,
|
|
plus the worst-case number of characters needed to
|
|
represent the value in decimal, plus one for the NUL. this
|
|
should avoid buffer overflows entirely: */
|
|
if (prf_flag_ls[0] == '\0') {
|
|
prf_value_d = va_arg(prf_args, int);
|
|
prf_value_buffer = tme_new(char, prf_width + ((sizeof(prf_value_d) * 3) + 1));
|
|
sprintf(prf_value_buffer, prf_format_buffer, prf_value_d);
|
|
PRF_OUT_ARG_CODE(TME_LOG_ARG_CODE_INT);
|
|
}
|
|
else if (prf_flag_ls[1] == '\0') {
|
|
prf_value_ld = va_arg(prf_args, long int);
|
|
prf_value_buffer = tme_new(char, prf_width + ((sizeof(prf_value_ld) * 3) + 1));
|
|
sprintf(prf_value_buffer, prf_format_buffer, prf_value_ld);
|
|
PRF_OUT_ARG_CODE(TME_LOG_ARG_CODE_LONG_INT);
|
|
}
|
|
else {
|
|
#if (0 prf_lld(+ 1))
|
|
prf_value_lld = va_arg(prf_args, long long int);
|
|
prf_value_buffer = tme_new(char, prf_width + ((sizeof(prf_value_lld) * 3) + 1));
|
|
sprintf(prf_value_buffer, prf_format_buffer, prf_value_lld);
|
|
PRF_OUT_ARG_CODE(TME_LOG_ARG_CODE_LONG_LONG_INT);
|
|
#else /* long long int not supported */
|
|
abort();
|
|
#endif /* long long int not supported */
|
|
}
|
|
PRF_OUT_MEM(prf_value_buffer, strlen(prf_value_buffer));
|
|
tme_free(prf_value_buffer);
|
|
|
|
/* enter state zero: */
|
|
prf_agg = prf_format;
|
|
prf_state = 0;
|
|
break;
|
|
|
|
/* the 's' conversion: */
|
|
case 's':
|
|
prf_value_s = va_arg(prf_args, const char *);
|
|
PRF_OUT_ARG_CODE(TME_LOG_ARG_CODE_STRING);
|
|
PRF_OUT_MEM(prf_value_s, strlen(prf_value_s));
|
|
|
|
/* enter state zero: */
|
|
prf_agg = prf_format;
|
|
prf_state = 0;
|
|
break;
|
|
|
|
/* the 'c' conversion: */
|
|
case 'c':
|
|
prf_value_c = va_arg(prf_args, int);
|
|
PRF_OUT_ARG_CODE(TME_LOG_ARG_CODE_CHAR);
|
|
PRF_OUT_CHAR(prf_value_c);
|
|
|
|
/* enter state zero: */
|
|
prf_agg = prf_format;
|
|
prf_state = 0;
|
|
break;
|
|
|
|
/* ignore anything else: */
|
|
default:
|
|
prf_agg = prf_format;
|
|
prf_state = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
}
|
|
|
|
/* end the variable arguments: */
|
|
va_end(prf_args);
|
|
}
|