snprintf支持格式化结构体

This commit is contained in:
guo_peixu
2022-06-07 16:26:10 +08:00
parent b677bb6c71
commit 20f3fb58b7
9 changed files with 2167 additions and 66 deletions

View File

@@ -6,6 +6,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
void *sample_handle = NULL;
void *test_handle = NULL;
@@ -19,50 +20,67 @@ int g_thread_num = 0;
const char *g_zlog_conf = NULL;
volatile long g_start_time = 0;
volatile long g_end_time = 0;
struct test_A{
int a;
char *str;
long long b;
};
int MESA_fmt_handler_A(void *info, char *buf, int maxlen)
{
struct test_A *obj = (struct test_A *)info;
int n = snprintf(buf, maxlen, "a=%d,s=%s,b=%lld", obj->a, obj->str, obj->b);
return n < maxlen?n:maxlen - 1;
}
void call_logger(int log_num, int thread_num)
{
int i = 0;
struct timespec start, end;
long start_time, end_time, time_cost;
clock_gettime(CLOCK_MONOTONIC, &start);
start_time = start.tv_sec*1000000 + start.tv_nsec/1000;
if(g_start_time == 0)
struct test_A a;
a.a = 10;
a.str = "hello";
a.b = 123456;
int i = 0;
struct timespec start, end;
long start_time, end_time, time_cost;
clock_gettime(CLOCK_MONOTONIC, &start);
start_time = start.tv_sec*1000000 + start.tv_nsec/1000;
if(g_start_time == 0)
{
g_start_time = start_time;
}
else
{
if(g_start_time > start_time)
{
g_start_time = start_time;
}
else
{
if(g_start_time > start_time)
{
g_start_time = start_time;
}
}
for(i = 0; i < log_num; i++)
{
MESA_handle_runtime_log(sample_handle, RLOG_LV_DEBUG, "sample", "sample_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num);
//sleep(1);
MESA_handle_runtime_log(test_handle, RLOG_LV_INFO, "test", "test_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num);
//MESA_HANDLE_RUNTIME_LOG(sample_handle, RLOG_LV_FATAL, "sample", "sample_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num);
//sleep(1);
//MESA_HANDLE_RUNTIME_LOG(test_handle, RLOG_LV_FATAL, "test", "test_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num);
}
clock_gettime(CLOCK_MONOTONIC, &end);
end_time = end.tv_sec*1000000 + end.tv_nsec/1000;
if(g_end_time == 0)
}
for(i = 0; i < log_num; i++)
{
//MESA_handle_runtime_log(sample_handle, RLOG_LV_DEBUG, "sample", "sample_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num);
//sleep(1);
//MESA_handle_runtime_log(test_handle, RLOG_LV_INFO, "test", "test_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num);
MESA_HANDLE_RUNTIME_LOG(sample_handle, RLOG_LV_FATAL, "sample", "sample_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num);
//sleep(1);
MESA_HANDLE_RUNTIME_LOG(test_handle, RLOG_LV_FATAL, "test", "test_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num);
MESA_HANDLE_RUNTIME_LOG(sample_handle, RLOG_LV_FATAL, "sample", "sample_handle RUNTIEM_LOG test, i = %d, thread_num = %d,struct a =%A", i, thread_num, &a);
}
clock_gettime(CLOCK_MONOTONIC, &end);
end_time = end.tv_sec*1000000 + end.tv_nsec/1000;
if(g_end_time == 0)
{
g_end_time = end_time;
}
else
{
if(g_end_time < end_time)
{
g_end_time = end_time;
}
else
{
if(g_end_time < end_time)
{
g_end_time = end_time;
}
}
time_cost = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000 ;
printf("THREAD %d write %d log using %ld us, avg speed %f /s, %ld -> %ld\n", thread_num, log_num, time_cost, ((float)log_num/(float)time_cost)*1000000, start_time, end_time);
return;
}
time_cost = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000 ;
printf("THREAD %d write %d log using %ld us, avg speed %f /s, %ld -> %ld\n", thread_num, log_num, time_cost, ((float)log_num/(float)time_cost)*1000000, start_time, end_time);
return;
}
@@ -129,26 +147,30 @@ int main(int argc, char ** args)
{
printf("get log sample_handle error\n");
return -1;
}
test_handle = MESA_create_runtime_log_handle("./log/test_log", RLOG_LV_DEBUG);
if(test_handle == NULL)
{
printf("get log test_handle error\n");
return -1;
}
for(i = 0; i < g_thread_num; i++)
{
pthread_create(&t[i], NULL, thread_logger, (void *)(unsigned long)(i));
}
signal(SIGINT, sig_int_handler);
signal(SIGHUP, sig_hup_handler);
while(1)
;
//MESA_destroy_runtime_log_handle(sample_handle);
//MESA_destroy_runtime_log_handle(test_handle);
//sample_handle = NULL;
//test_handle = NULL;
}
if(MESA_handle_fmt_rule_register(sample_handle, 'A', MESA_fmt_handler_A, 512) < 0){
printf("struct a register error\n");
return 0;
}
test_handle = MESA_create_runtime_log_handle("./log/test_log", RLOG_LV_DEBUG);
if(test_handle == NULL)
{
printf("get log test_handle error\n");
return -1;
}
for(i = 0; i < g_thread_num; i++)
{
pthread_create(&t[i], NULL, thread_logger, (void *)(unsigned long)(i));
}
signal(SIGINT, sig_int_handler);
signal(SIGHUP, sig_hup_handler);
while(1)
;
//MESA_destroy_runtime_log_handle(sample_handle);
//MESA_destroy_runtime_log_handle(test_handle);
//sample_handle = NULL;
//test_handle = NULL;
return 0;
}

View File

@@ -14,6 +14,19 @@ extern "C"
{
#endif
#include <pthread.h>
#define MESA_PTHREAD_CACHE_BUF_DEFAULT_LEN 1024
#define MESA_PTHREAD_FMT_BUF_DEFAULT_LEN 256
extern pthread_key_t MESA_pthread_key;
void MESA_pthread_free_handler(void *arg);
typedef int (*MESA_fmt_handler)(void *info, char *buf, int buflen);
int MESA_handle_fmt_rule_register(void *handle, char sign, MESA_fmt_handler handler, int buflen);
int MESA_handle_check_fmt_sign(void *handle, char sign, MESA_fmt_handler *handler, char **buf, int *maxlen);
void MESA_free_pthread_private(void *arg);
#define RLOG_LV_DEBUG 10
#define RLOG_LV_INFO 20
#define RLOG_LV_FATAL 30
@@ -21,7 +34,7 @@ extern "C"
int MESA_handle_runtime_log_creation(const char *conf_path);
int MESA_handle_runtime_log_reconstruction(const char *conf_path);
void MESA_handle_runtime_log_destruction();
void MESA_handle_runtime_log_destruction(void);
#define MESA_HANDLE_RUNTIME_LOG(handle, lv, mod, fmt, args...) \
MESA_handle_runtime_log((handle), (lv), (mod), "file %s, line %d, " fmt, \

24
inc/snprintf.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef _PORTABLE_SNPRINTF_H_
#define _PORTABLE_SNPRINTF_H_
#define PORTABLE_SNPRINTF_VERSION_MAJOR 2
#define PORTABLE_SNPRINTF_VERSION_MINOR 2
#ifdef HAVE_SNPRINTF
#include <stdio.h>
#else
extern int snprintf(char *, size_t, const char *, /*args*/ ...);
extern int vsnprintf(char *, size_t, const char *, va_list);
#endif
#if defined(HAVE_SNPRINTF) && defined(PREFER_PORTABLE_SNPRINTF)
extern int portable_snprintf(void * handle, char *str, size_t str_m, const char *fmt, /*args*/ ...);
extern int portable_vsnprintf(void *handle, char *str, size_t str_m, const char *fmt, va_list ap);
/*#define snprintf portable_snprintf*/ /*others use libc snprintf*/
/*#define vsnprintf portable_vsnprintf*/
#endif
extern int asprintf (void * handle, char **ptr, const char *fmt, /*args*/ ...);
extern int vasprintf (void * handle, char **ptr, const char *fmt, va_list ap);
extern int asnprintf (void * handle, char **ptr, size_t str_m, const char *fmt, /*args*/ ...);
extern int vasnprintf(void * handle, char **ptr, size_t str_m, const char *fmt, va_list ap);
#endif

View File

@@ -1,6 +1,9 @@
#include "MESA_handle_logger.h"
#include "snprintf.h"
#include "zlog.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -14,12 +17,30 @@ static int g_zlog_conf_fp = -1;
static char global_conf_filepath[MAX_HANDLE_LOG_PATH] = "";
static char tmp_conf_filepath[MAX_HANDLE_LOG_PATH] = "";
#define MESA_FORMAT_RULE_MAX 16
pthread_key_t MESA_pthread_key;
pthread_once_t MESA_pthread_key_once = PTHREAD_ONCE_INIT;
struct MESA_pthread_private{
char *fmt_buf;
char *cache_buf;
int fmt_buf_len;
int cache_buf_len;
};
struct MESA_fmt_obj{
char sign;
MESA_fmt_handler handler;
};
typedef struct log_handle_t
{
int runtime_log_level;
int fmt_rule_num;
zlog_category_t *zc;
const char *global_conf_path;
char runtime_log_file[MAX_HANDLE_LOG_PATH];
int fmt_buf_len;
struct MESA_fmt_obj fmt_rule[MESA_FORMAT_RULE_MAX];
} log_handle_t;
@@ -127,6 +148,7 @@ static const char *loglevel_to_name(int level)
static void snapshot_handle_info(const char *handle_name, const char *log_path, int level)
{
int n = 0;
char zlog_rule_conf_content[MAX_HANDLE_LOG_PATH + 1] = "";
static char *tmp_prefix = "/tmp/MESA_handle_logger/";
static char *zlog_conf_init_buff = "[global]\ndefault format = \"%d(%c), %V, %F, %U, %m%n\" \n[levels]\nDEBUG=10\nINFO=20\nFATAL=30\n[rules]";
@@ -145,13 +167,22 @@ static void snapshot_handle_info(const char *handle_name, const char *log_path,
{
return;
}
write(g_zlog_conf_fp, zlog_conf_init_buff, strlen(zlog_conf_init_buff));
n = write(g_zlog_conf_fp, zlog_conf_init_buff, strlen(zlog_conf_init_buff));
if(n < 0){
fprintf(stderr,"write g_zlog_conf_fp error, func=%s, line=%d\n",__FUNCTION__, __LINE__);
}
fsync(g_zlog_conf_fp);
}
snprintf(zlog_rule_conf_content, sizeof(zlog_rule_conf_content),
n = snprintf(zlog_rule_conf_content, sizeof(zlog_rule_conf_content),
"\n%s.%s \"%s.%%d(%%F)\"",
handle_name, loglevel_to_name(level), log_path);
write(g_zlog_conf_fp, zlog_rule_conf_content, strlen(zlog_rule_conf_content));
if(n > 0){
n = write(g_zlog_conf_fp, zlog_rule_conf_content, strlen(zlog_rule_conf_content));
if(n < 0){
fprintf(stderr,"write g_zlog_conf_fp error, func=%s, line=%d\n",__FUNCTION__, __LINE__);
}
}
fsync(g_zlog_conf_fp);
if(g_zlog_inited == 0)
@@ -162,15 +193,70 @@ static void snapshot_handle_info(const char *handle_name, const char *log_path,
}
return;
}
struct MESA_pthread_private *MESA_create_pthread_private(void *handle)
{
log_handle_t *p_handle = (log_handle_t *)handle;
struct MESA_pthread_private *pri = malloc(sizeof(struct MESA_pthread_private));
if(pri == NULL){
return NULL;
}
memset(pri, 0 ,sizeof(struct MESA_pthread_private));
pri->fmt_buf = malloc(p_handle->fmt_buf_len);
if(pri->fmt_buf == NULL){
goto error;
}
pri->fmt_buf_len = p_handle->fmt_buf_len;
pri->cache_buf_len = MESA_PTHREAD_CACHE_BUF_DEFAULT_LEN;
pri->cache_buf = malloc(pri->cache_buf_len);
if(pri->cache_buf == NULL){
goto error;
}
return pri;
error:
if(pri->fmt_buf){
free(pri->fmt_buf);
}
if(pri->cache_buf){
free(pri->cache_buf);
}
if(pri){
free(pri);
}
return NULL;
}
void MESA_free_pthread_private(void *arg)
{
struct MESA_pthread_private *pri = (struct MESA_pthread_private *)arg;
if(pri == NULL){
return ;
}
if(pri->fmt_buf){
free(pri->fmt_buf);
}
if(pri->cache_buf){
free(pri->cache_buf);
}
if(pri){
free(pri);
}
return ;
}
void MESA_alloc_pthread_key()
{
pthread_key_create(&MESA_pthread_key, MESA_free_pthread_private);
return ;
}
void *MESA_create_runtime_log_handle(const char *file_path, int level)
{
if(file_path == NULL)
return NULL;
int rc = -1;
zlog_category_t *zc = NULL;
FILE *fp = NULL;
log_handle_t *p_handle = NULL;
char handle_name[MAX_HANDLE_LOG_PATH];
@@ -199,6 +285,8 @@ void *MESA_create_runtime_log_handle(const char *file_path, int level)
strncpy(p_handle->runtime_log_file, file_path, sizeof(p_handle->runtime_log_file) - 1);
p_handle->runtime_log_level = level;
p_handle->zc = zc;
p_handle->fmt_buf_len = MESA_PTHREAD_FMT_BUF_DEFAULT_LEN;
pthread_once(&MESA_pthread_key_once, MESA_alloc_pthread_key);
return (void *)p_handle;
}
@@ -224,9 +312,31 @@ void MESA_handle_runtime_log(void *handle, int level, const char *module, const
if(p_handle->zc == NULL)return;
va_list ap;
va_list ap_bk;
va_start(ap, fmt);
vzlog(p_handle->zc, p_handle->runtime_log_file, strlen(p_handle->runtime_log_file), module, strlen(module), __LINE__, level, fmt, ap);
va_end(ap);
struct MESA_pthread_private *pri = (struct MESA_pthread_private *)pthread_getspecific(MESA_pthread_key);
if(pri == NULL){
pri = MESA_create_pthread_private(handle);
if(pri == NULL){
return ;
}
pthread_setspecific(MESA_pthread_key,(void*)pri);
}
va_copy(ap_bk, ap);
int n = portable_vsnprintf(handle, pri->cache_buf, pri->cache_buf_len, fmt, ap_bk);
if(n >= pri->cache_buf_len){
char *p = realloc(pri->cache_buf, n + 1);
if(p != NULL){
pri->cache_buf_len = n + 1;
pri->cache_buf = p;
va_copy(ap_bk, ap);
portable_vsnprintf(handle, pri->cache_buf, pri->cache_buf_len, fmt, ap_bk);
}
}
va_end(ap);
va_end(ap_bk);
zlog(p_handle->zc, p_handle->runtime_log_file, strlen(p_handle->runtime_log_file), module, strlen(module), __LINE__, level, "%s", pri->cache_buf);
return ;
}
@@ -328,3 +438,51 @@ void MESA_handle_runtime_log_destruction()
close(g_zlog_conf_fp);
}
}
int MESA_handle_fmt_rule_register(void *handle, char sign, MESA_fmt_handler handler, int buflen)
{
log_handle_t *p_handle = (log_handle_t *)handle;
int fmt_rule_num = p_handle->fmt_rule_num;
if(fmt_rule_num >= MESA_FORMAT_RULE_MAX){
return -1;
}
p_handle->fmt_rule[fmt_rule_num].sign = sign;
p_handle->fmt_rule[fmt_rule_num].handler = handler;
p_handle->fmt_rule_num++;
if(buflen > 0 && buflen > p_handle->fmt_buf_len){
p_handle->fmt_buf_len = buflen;
}
return 0;
}
int MESA_handle_check_fmt_sign(void *handle, char sign, MESA_fmt_handler *handler, char**buf, int *maxlen)
{
if(!handle || !handler){
return 0;
}
struct MESA_pthread_private *pthread_pri = NULL;
log_handle_t *p_handle = (log_handle_t *)handle;
int fmt_rule_num = p_handle->fmt_rule_num;
int i = 0;
for(i = 0; i < fmt_rule_num; i++){
if(p_handle->fmt_rule[i].sign == sign){
pthread_pri = (struct MESA_pthread_private *)pthread_getspecific(MESA_pthread_key);
if(pthread_pri == NULL){
return 0;
}
*handler = p_handle->fmt_rule[i].handler;
if(p_handle->fmt_buf_len > pthread_pri->fmt_buf_len){
char *p = realloc(pthread_pri->fmt_buf, p_handle->fmt_buf_len);
if(p != NULL){
pthread_pri->fmt_buf = p;
pthread_pri->fmt_buf_len = p_handle->fmt_buf_len;
}
}
*buf = pthread_pri->fmt_buf;
*maxlen = pthread_pri->fmt_buf_len;
return 1;
}
}
return 0;
}

View File

@@ -0,0 +1,121 @@
The Frontier Artistic License Version 1.0
Derived from the Artistic License at OpenSource.org.
Submitted to OpenSource.org for Open Source Initiative certification.
Preamble
The intent of this document is to state the conditions under which a
Package may be copied, such that the Copyright Holder maintains some
semblance of artistic control over the development of the package,
while giving the users of the package the right to use and distribute
the Package in a more-or-less customary fashion, plus the right to
make reasonable modifications.
Definitions
"Package" refers to the script, suite, file, or collection of
scripts, suites, and/or files distributed by the Copyright Holder,
and to derivatives of that Package created through textual modification.
"Standard Version" refers to such a Package if it has not been
modified, or has been modified in accordance with the wishes of
the Copyright Holder.
"Copyright Holder" is whoever is named in the copyright statement
or statements for the package.
"You" is you, if you're thinking about copying or distributing
this Package.
"Reasonable copying fee" is whatever you can justify on the basis
of media cost, duplication charges, time of people involved, and
so on. (You will not be required to justify it to the Copyright
Holder, but only to the computing community at large as a market
that must bear the fee.)
"Freely Available" means that no fee is charged for the item
itself, though there may be fees involved in handling the item.
It also means that recipients of the item may redistribute it under
the same conditions they received it.
Terms
1. You may make and give away verbatim copies of the source form of
the Standard Version of this Package without restriction, provided
that you duplicate all of the original copyright notices and
associated disclaimers.
2. You may apply bug fixes, portability fixes, and other modifications
derived from the Public Domain or from the Copyright Holder. A Package
modified in such a way shall still be considered the Standard Version.
3. You may otherwise modify your copy of this Package in any way,
provided that you insert a prominent notice in each changed script,
suite, or file stating how and when you changed that script, suite,
or file, and provided that you do at least ONE of the following:
a) Use the modified Package only within your corporation or
organization, or retain the modified Package solely for personal use.
b) Place your modifications in the Public Domain or otherwise make
them Freely Available, such as by posting said modifications to Usenet
or an equivalent medium, or placing the modifications on a major archive
site such as ftp.uu.net, or by allowing the Copyright Holder to include
your modifications in the Standard Version of the Package.
c) Rename any non-standard executables so the names do not conflict
with standard executables, which must also be provided, and provide
a separate manual page (or equivalent) for each non-standard executable
that clearly documents how it differs from the Standard Version.
d) Make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the following:
a) Distribute a Standard Version of the executables and library
files, together with instructions (in the manual page or
equivalent) on where to get the Standard Version.
b) Accompany the distribution with the machine-readable source of
the Package with your modifications.
c) Accompany any non-standard executables with their corresponding
Standard Version executables, give the non-standard executables
non-standard names, and clearly document the differences in manual
pages (or equivalent), together with instructions on where to get
the Standard Version.
d) Make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of
this Package. You may charge any fee you choose for support of this
Package. You may not charge a fee for this Package itself. However,
you may distribute this Package in aggregate with other (possibly
commercial) programs as part of a larger (possibly commercial)
software distribution provided that you do not advertise this Package
as a product of your own.
6. The scripts and library files supplied as input to or produced as
output from the programs of this Package do not automatically fall
under the copyright of this Package, but belong to whomever generated
them, and may be sold commercially, and may be aggregated with this
Package.
7. Scripts, suites, or programs supplied by you that depend on or
otherwise make use of this Package shall not be considered part of
this Package.
8. The name of the Copyright Holder may not be used to endorse or
promote products derived from this software without specific prior
written permission.
9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End
http://www.spinwardstars.com/frontier/fal.html

View File

@@ -0,0 +1,54 @@
# Make sure you include -DHAVE_SNPRINTF in CFLAGS if your system
# does have snprintf!
# If you need (long long int) support and you sprintf supports it,
# define -DSNPRINTF_LONGLONG_SUPPORT
vpath %.h ../../inc
vpath %.a ../../lib
CC = gcc
CFLAGS = -DPREFER_PORTABLE_SNPRINTF -O3 \
-Wall -Wpointer-arith -Wwrite-strings \
-Wcast-qual -Wcast-align -Waggregate-return \
-Wmissing-prototypes -Wmissing-declarations \
-Wshadow -Wstrict-prototypes
CFLAGS+=-DSNPRINTF_LONGLONG_SUPPORT -DHAVE_SNPRINTF
CFLAGS+=-I../../inc/
# -DNEED_ASPRINTF -DNEED_ASNPRINTF -DNEED_VASPRINTF -DNEED_VASNPRINTF
# -DNEED_SNPRINTF_ONLY
# Digital Unix: native compiler usually produces better code than gcc
#CC = cc
#CFLAGS = -DPREFER_PORTABLE_SNPRINTF -O4 -std1 -arch host
# Recommend to leave COMPATIBILITY empty for normal use.
# Should be set for bug compatibility when running tests
# too keep them less chatty.
COMPATIBILITY =
#COMPATIBILITY = -DSOLARIS_BUG_COMPATIBLE
#COMPATIBILITY = -DHPUX_BUG_COMPATIBLE
#COMPATIBILITY = -DDIGITAL_UNIX_BUG_COMPATIBLE
#COMPATIBILITY = -DPERL_BUG_COMPATIBLE
#COMPATIBILITY = -DLINUX_COMPATIBLE
SRC=snprintf.c
OBJS=$(SRC:.c=.o)
TARGET=libMESA_snprintf.a libMESA_snprintf.so
all:$(TARGET)
cp -f $(TARGET) ../../lib
libMESA_snprintf.a:$(OBJS)
ar cqs $@ $<
libMESA_snprintf.so:$(OBJS)
$(CC) $(CFLAGS) $(LIB) -shared $< -o $@
.c.o:
clean :
rm -f $(OBJS) $(TARGET)

View File

@@ -0,0 +1,283 @@
snprintf.c
- a portable implementation of snprintf,
including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf
snprintf is a routine to convert numeric and string arguments to
formatted strings. It is similar to sprintf(3) provided in a system's
C library, yet it requires an additional argument - the buffer size -
and it guarantees never to store anything beyond the given buffer,
regardless of the format or arguments to be formatted. Some newer
operating systems do provide snprintf in their C library, but many do
not or do provide an inadequate (slow or idiosyncratic) version, which
calls for a portable implementation of this routine.
Author
Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000
Copyright <20> 1999, Mark Martinec
Terms and conditions ...
This program is free software; you can redistribute it and/or modify
it under the terms of the Frontier Artistic License which comes with
this Kit.
Features
* careful adherence to specs regarding flags, field width and
precision;
* good performance for large string handling (large format, large
argument or large paddings). Performance is similar to system's
sprintf and in several cases significantly better (make sure you
compile with optimizations turned on, tell the compiler the code
is strict ANSI if necessary to give it more freedom for
optimizations);
* return value semantics per ISO/IEC 9899:1999 ("ISO C99");
* written in standard ISO/ANSI C - requires an ANSI C compiler.
Supported conversion specifiers and data types
This snprintf only supports the following conversion specifiers: s, c,
d, o, u, x, X, p (and synonyms: i, D, U, O - see below) with flags:
'-', '+', ' ', '0' and '#'. An asterisk is supported for field width
as well as precision.
Length modifiers 'h' (short int), 'l' (long int), and 'll' (long long
int) are supported.
NOTE:
If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the
length modifier 'll' is recognized but treated the same as 'l',
which may cause argument value truncation! Defining
SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also
handles length modifier 'll'. long long int is a language extension
which may not be portable.
Conversion of numeric data (conversion specifiers d, o, u, x, X, p)
with length modifiers (none or h, l, ll) is left to the system routine
sprintf, but all handling of flags, field width and precision as well
as c and s conversions is done very carefully by this portable
routine. If a string precision (truncation) is specified (e.g. %.8s)
it is guaranteed the string beyond the specified precision will not be
referenced.
Length modifiers h, l and ll are ignored for c and s conversions (data
types wint_t and wchar_t are not supported).
The following common synonyms for conversion characters are supported:
* i is a synonym for d
* D is a synonym for ld, explicit length modifiers are ignored
* U is a synonym for lu, explicit length modifiers are ignored
* O is a synonym for lo, explicit length modifiers are ignored
The D, O and U conversion characters are nonstandard, they are
supported for backward compatibility only, and should not be used for
new code.
The following is specifically not supported:
* flag ' (thousands' grouping character) is recognized but ignored
* numeric conversion specifiers: f, e, E, g, G and synonym F, as
well as the new a and A conversion specifiers
* length modifier 'L' (long double) and 'q' (quad - use 'll'
instead)
* wide character/string conversions: lc, ls, and nonstandard
synonyms C and S
* writeback of converted string length: conversion character n
* the n$ specification for direct reference to n-th argument
* locales
It is permitted for str_m to be zero, and it is permitted to specify
NULL pointer for resulting string argument if str_m is zero (as per
ISO C99).
The return value is the number of characters which would be generated
for the given input, excluding the trailing null. If this value is
greater or equal to str_m, not all characters from the result have
been stored in str, output bytes beyond the (str_m-1) -th character
are discarded. If str_m is greater than zero it is guaranteed the
resulting string will be null-terminated.
NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
but is different from some older and vendor implementations, and is
also different from XPG, XSH5, SUSv2 specifications. For historical
discussion on changes in the semantics and standards of snprintf see
printf(3) man page in the Linux programmers manual.
Routines asprintf and vasprintf return a pointer (in the ptr argument)
to a buffer sufficiently large to hold the resulting string. This
pointer should be passed to free(3) to release the allocated storage
when it is no longer needed. If sufficient space cannot be allocated,
these functions will return -1 and set ptr to be a NULL pointer. These
two routines are a GNU C library extensions (glibc).
Routines asnprintf and vasnprintf are similar to asprintf and
vasprintf, yet, like snprintf and vsnprintf counterparts, will write
at most str_m-1 characters into the allocated output string, the last
character in the allocated buffer then gets the terminating null. If
the formatted string length (the return value) is greater than or
equal to the str_m argument, the resulting string was truncated and
some of the formatted characters were discarded. These routines
present a handy way to limit the amount of allocated memory to some
sane value.
Availability
http://www.ijs.si/software/snprintf/
* snprintf_1.3.tar.gz (1999-06-30), md5 sum: snprintf_1.3.tar.gz.md5
* snprintf_2.1.tar.gz (2000-07-14), md5 sum: snprintf_2.1.tar.gz.md5
* snprintf_2.2.tar.gz (2000-10-18), md5 sum: snprintf_2.2.tar.gz.md5
Mailing list
There is a very low-traffic mailing list snprintf-announce@ijs.si
where announcements about new versions will be posted as well as
warnings about threatening bugs if discovered. The posting is
restricted to snprintf developer(s).
To subscribe to (or unsubscribe from) the mailing list please visit
the list server's web page
http://mailman.ijs.si/listinfo/snprintf-announce
You can also subscribe to the list by mailing the command SUBSCRIBE
either in the subject or in the message body to the address
snprintf-announce-request@ijs.si . You will be asked for confirmation
before subscription will be effective.
The list of members is only accessible to the list administrator, so
there is no need for concern about automatic e-mail address gatherers.
Questions about the mailing list and concerns for the attention of a
person should be sent to snprintf-announce-admin@ijs.si
There is no general discussion list about portable snprintf at the
moment. Please send comments and suggestion to the author.
Revision history
Version 1.3 fixes a runaway loop problem from 1.2. Please upgrade.
1999-06-30 V1.3 Mark Martinec <mark.martinec@ijs.si>
+ fixed runaway loop (eventually crashing when str_l wraps
beyond 2^31) while copying format string without conversion
specifiers to a buffer that is too short (thanks to Edwin
Young <edwiny@autonomy.com> for spotting the problem);
+ added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) to
snprintf.h
2000-02-14 V2.0 (never released) Mark Martinec <mark.martinec@ijs.si>
+ relaxed license terms: The Artistic License now applies. You
may still apply the GNU GENERAL PUBLIC LICENSE as was
distributed with previous versions, if you prefer;
+ changed REVISION HISTORY dates to use ISO 8601 date format;
+ added vsnprintf (patch also independently proposed by Caol<6F>n
McNamara 2000-05-04, and Keith M Willenson 2000-06-01)
2000-06-27 V2.1 Mark Martinec <mark.martinec@ijs.si>
+ removed POSIX check for str_m < 1; value 0 for str_m is
allowed by ISO C99 (and GNU C library 2.1) (pointed out on
2000-05-04 by Caol<6F>n McNamara, caolan@ csn dot ul dot ie).
Besides relaxed license this change in standards adherence is
the main reason to bump up the major version number;
+ added nonstandard routines asnprintf, vasnprintf, asprintf,
vasprintf that dynamically allocate storage for the resulting
string; these routines are not compiled by default, see
comments where NEED_V?ASN?PRINTF macros are defined;
+ autoconf contributed by Caol<6F>n McNamara
2000-10-06 V2.2 Mark Martinec <mark.martinec@ijs.si>
+ BUG FIX: the %c conversion used a temporary variable that was
no longer in scope when referenced, possibly causing
incorrect resulting character;
+ BUG FIX: make precision and minimal field width unsigned to
handle huge values (2^31 <= n < 2^32) correctly; also be more
careful in the use of signed/unsigned/size_t internal
variables -- probably more careful than many vendor
implementations, but there may still be a case where huge
values of str_m, precision or minimal field could cause
incorrect behaviour;
+ use separate variables for signed/unsigned arguments, and for
short/int, long, and long long argument lengths to avoid
possible incompatibilities on certain computer architectures.
Also use separate variable arg_sign to hold sign of a numeric
argument, to make code more transparent;
+ some fiddling with zero padding and "0x" to make it Linux
compatible;
+ systematically use macros fast_memcpy and fast_memset instead
of case-by-case hand optimization; determine some breakeven
string lengths for different architectures;
+ terminology change: format -> conversion specifier, C9x ->
ISO/IEC 9899:1999 ("ISO C99"), alternative form -> alternate
form, data type modifier -> length modifier;
+ several comments rephrased and new ones added;
+ make compiler not complain about 'credits' defined but not
used;
Other implementations of snprintf
I am aware of some other (more or less) portable implementations of
snprintf. I do not claim they are free software - please refer to
their respective copyright and licensing terms. If you know of other
versions please let me know.
* a very thorough implementation (src/util_snprintf.c) by the Apache
Group distributed with the Apache web server -
http://www.apache.org/ . Does its own floating point conversions
using routines ecvt(3), fcvt(3) and gcvt(3) from the standard C
library or from the GNU libc.
This is from the code:
This software [...] was originally based on public domain software
written at the National Center for Supercomputing Applications,
University of Illinois, Urbana-Champaign.
[...] This code is based on, and used with the permission of, the
SIO stdio-replacement strx_* functions by Panos Tsirigotis
<panos@alumni.cs.colorado.edu> for xinetd.
* QCI Utilities use a modified version of snprintf from the Apache
group.
* implementations as distributed with OpenBSD, FreeBSD, and NetBSD
are all wrappers to vfprintf.c, which is derived from software
contributed to Berkeley by Chris Torek.
* implementation from Prof. Patrick Powell <papowell@sdsu.edu>,
Dept. Electrical and Computer Engineering, San Diego State
University, San Diego, CA 92182-1309, published in Bugtraq
archives for 3rd quarter (Jul-Aug) 1995. No floating point
conversions.
* Brandon Long's <blong@fiction.net> modified version of Prof.
Patrick Powell's snprintf with contributions from others. With
minimal floating point support.
* implementation (src/snprintf.c) as distributed with sendmail -
http://www.sendmail.org/ is a cleaned up Prof. Patrick Powell's
version to compile properly and to support .precision and %lx.
* implementation from Caol<6F>n McNamara available at
http://www.csn.ul.ie/~caolan/publink/snprintf-1.1.tar.gz, handles
floating point.
* implementation used by newlog (a replacement for syslog(3)) made
available by the SOS Corporation. Enabling floating point support
is a compile-time option.
* implementation by Michael Richardson <mcr@metis.milkyway.com> is
available at http://sandelman.ottawa.on.ca/SSW/snp/snp.html. It is
based on BSD44-lite's vfprintf() call, modified to function on
SunOS. Needs internal routines from the 4.4 strtod (included),
requires GCC to compile the long long (aka quad_t) portions.
* implementation from Tomi Salo <ttsalo@ssh.fi> distributed with SSH
2.0 Unix Server. Not in public domain. Floating point conversions
done by system's sprintf.
* and for completeness: my portable version described in this very
document available at http://www.ijs.si/software/snprintf/ .
In retrospect, it appears that a lot of effort was wasted by many
people for not being aware of what others are doing. Sigh.
Also of interest: The Approved Base Working Group Resolution for XSH5,
Ref: bwg98-006, Topic: snprintf.
_________________________________________________________________
mm
Last updated: 2000-10-18
Valid HTML 4.0!

View File

@@ -0,0 +1,382 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<link rev="made" href="mailto:mark.martinec@ijs.si">
<title>
snprintf.c - a portable implementation of snprintf
(including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf)
</title>
<meta http-equiv="Content-Language" content="en">
<meta name="author" content="Mark Martinec">
<meta name="copyright" content="Copyright 2000 Mark Martinec, All Rights Reserved">
<meta name="date" content="2000-10-18">
<meta name="keywords" lang="en"
content="snprintf,portable,vsnprintf,asnprintf,vasnprintf,asprintf,vasprintf
ISO/IEC 9899:1999,ISO C99,ISO C9x,POSIX">
<style type="text/css">
<!--
body { background: white; color: black }
-->
</style>
</head>
<body>
<h1><b>snprintf.c</b>
<br> - a portable implementation of snprintf,
<br><font size="+1">including
vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf</font>
</h1>
<p><b>snprintf</b> is a routine to convert numeric and string arguments
to formatted strings. It is similar to sprintf(3) provided in a
system's C library, yet it requires an additional argument - the buffer
size - and it guarantees never to store anything beyond the given buffer,
regardless of the format or arguments to be formatted. Some newer
operating systems do provide <b>snprintf</b> in their C library,
but many do not or do provide an inadequate (slow or idiosyncratic)
version, which calls for a portable implementation of this routine.
<h2>Author</h2>
<p><a href="http://www.ijs.si/people/mark/">Mark Martinec</a>
&lt;<a href="mailto:mark.martinec@ijs.si">mark.martinec@ijs.si</a>&gt;,
April 1999, June 2000
<br>Copyright &copy; 1999, Mark Martinec
<h2>Terms and conditions ...</h2>
<p>This program is free software; you can redistribute it
and/or modify it under the terms of the
<i><a href="./LICENSE.txt">Frontier Artistic License</a></i>
which comes with this Kit.
<h2>Features</h2>
<ul>
<li>careful adherence to specs regarding flags, field width and precision;
<li>good performance for large string handling (large format, large argument
or large paddings). Performance is similar to system's <b>sprintf</b>
and in several cases significantly better (make sure you compile with
optimizations turned on, tell the compiler the code is strict ANSI
if necessary to give it more freedom for optimizations);
<li>return value semantics per ISO/IEC 9899:1999 ("ISO C99");
<li>written in standard ISO/ANSI C - requires an ANSI C compiler.
</ul>
<h2>Supported conversion specifiers and data types</h2>
<p>This <b>snprintf</b> only supports the following conversion specifiers:
s, c, d, o, u, x, X, p (and synonyms: i, D, U, O - see below)
with flags: '-', '+', '&nbsp;', '0' and '#'.
An asterisk is supported for field width as well as precision.
<p>Length modifiers 'h' (<i>short int</i>), 'l' (<i>long int</i>),
and 'll' (<i>long long int</i>) are supported.
<p>NOTE:
<blockquote>
If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default)
the length modifier 'll' is recognized but treated the same as 'l',
which may cause argument value truncation!
Defining SNPRINTF_LONGLONG_SUPPORT requires that your system's
<b>sprintf</b> also handles length modifier 'll'.
<i>long long int</i> is a language extension which may not be portable.
</blockquote>
<p>Conversion of numeric data (conversion specifiers d, o, u, x, X, p)
with length modifiers (none or h, l, ll) is left to the system
routine <b>sprintf</b>, but all handling of flags, field width and precision
as well as c and s conversions is done very carefully by this portable routine.
If a string precision (truncation) is specified (e.g. %.8s) it is
guaranteed the string beyond the specified precision will not be referenced.
<p>Length modifiers h, l and ll are ignored for c and s conversions
(data types <i>wint_t</i> and <i>wchar_t</i> are not supported).
<p>The following common synonyms for conversion characters are supported:
<ul>
<li>i is a synonym for d
<li>D is a synonym for ld, explicit length modifiers are ignored
<li>U is a synonym for lu, explicit length modifiers are ignored
<li>O is a synonym for lo, explicit length modifiers are ignored
</ul>
The D, O and U conversion characters are nonstandard, they are supported
for backward compatibility only, and should not be used for new code.
<p>The following is specifically <b>not</b> supported:
<ul>
<li>flag ' (thousands' grouping character) is recognized but ignored
<li>numeric conversion specifiers: f, e, E, g, G and synonym F,
as well as the new a and A conversion specifiers
<li>length modifier 'L' (<i>long double</i>)
and 'q' (<i>quad</i> - use 'll' instead)
<li>wide character/string conversions: lc, ls, and nonstandard
synonyms C and S
<li>writeback of converted string length: conversion character n
<li>the n$ specification for direct reference to n-th argument
<li>locales
</ul>
<p>It is permitted for str_m to be zero, and it is permitted to specify NULL
pointer for resulting string argument if str_m is zero (as per ISO C99).
<p>The return value is the number of characters which would be generated
for the given input, <i>excluding</i> the trailing null. If this value
is greater or equal to str_m, not all characters from the result
have been stored in str, output bytes beyond the (str_m-1) -th character
are discarded. If str_m is greater than zero it is guaranteed
the resulting string will be null-terminated.
<p>NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
but is different from some older and vendor implementations,
and is also different from XPG, XSH5, SUSv2 specifications.
For historical discussion on changes in the semantics and standards
of snprintf see printf(3) man page in the Linux programmers manual.
<p>Routines asprintf and vasprintf return a pointer (in the ptr argument)
to a buffer sufficiently large to hold the resulting string. This pointer
should be passed to free(3) to release the allocated storage when it is
no longer needed. If sufficient space cannot be allocated, these functions
will return -1 and set ptr to be a NULL pointer. These two routines are a
GNU C library extensions (glibc).
<p>Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
characters into the allocated output string, the last character in the
allocated buffer then gets the terminating null. If the formatted string
length (the return value) is greater than or equal to the str_m argument,
the resulting string was truncated and some of the formatted characters
were discarded. These routines present a handy way to limit the amount
of allocated memory to some sane value.
<h2>Availability</h2>
<p><a href="http://www.ijs.si/software/snprintf/"
>http://www.ijs.si/software/snprintf/</a>
<ul>
<li>
<a href="./snprintf_1.3.tar.gz">snprintf_1.3.tar.gz</a> (1999-06-30),
md5 sum: <a href="./snprintf_1.3.tar.gz.md5">snprintf_1.3.tar.gz.md5</a>
<li>
<a href="./snprintf_2.1.tar.gz">snprintf_2.1.tar.gz</a> (2000-07-14),
md5 sum: <a href="./snprintf_2.1.tar.gz.md5">snprintf_2.1.tar.gz.md5</a>
<li>
<a href="./snprintf_2.2.tar.gz">snprintf_2.2.tar.gz</a> (2000-10-18),
md5 sum: <a href="./snprintf_2.2.tar.gz.md5">snprintf_2.2.tar.gz.md5</a>
</ul>
<h2>Mailing list</h2>
<p>There is a very low-traffic mailing list <i>snprintf-announce@ijs.si</i>
where announcements about new versions will be posted
as well as warnings about threatening bugs if discovered.
The posting is restricted to snprintf developer(s).
<p>To subscribe to (or unsubscribe from) the mailing list
please visit the list server's web page
<a href="http://mailman.ijs.si/listinfo/snprintf-announce"
>http://mailman.ijs.si/listinfo/snprintf-announce</a>
<p>You can also subscribe to the list by mailing
the command SUBSCRIBE either in the subject or in the message body
to the address <a href="mailto:snprintf-announce-request@ijs.si"
>snprintf-announce-request@ijs.si</a> . You will be asked for
confirmation before subscription will be effective.
<p>The list of members is only accessible to the list administrator,
so there is no need for concern about automatic e-mail address gatherers.
<p>Questions about the mailing list and concerns for the attention
of a person should be sent to <a href="mailto:snprintf-announce-admin@ijs.si"
>snprintf-announce-admin@ijs.si</a>
<p>There is no <i>general</i> discussion list about portable snprintf
at the moment. Please send comments and suggestion to the author.
<h2>Revision history</h2>
<p><b>Version 1.3 fixes a runaway loop problem from 1.2. Please upgrade.</b>
<dl>
<dt>1999-06-30 V1.3 Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li>fixed runaway loop (eventually crashing when str_l wraps
beyond 2^31) while copying format string without
conversion specifiers to a buffer that is too short
(thanks to Edwin Young &lt;edwiny@autonomy.com&gt; for spotting the problem);
<li>added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) to snprintf.h
</ul>
<dt>2000-02-14 V2.0 (never released) Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li>relaxed license terms:
<a href="./LICENSE.txt">The Artistic License</a> now applies.
You may still apply the GNU GENERAL PUBLIC LICENSE
as was distributed with previous versions, if you prefer;
<li>changed REVISION HISTORY dates to use
<a href="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">ISO 8601
date format</a>;
<li>added vsnprintf (patch also independently proposed by
Caol&aacute;n McNamara 2000-05-04, and Keith M Willenson 2000-06-01)
</ul>
<dt>2000-06-27 V2.1 Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li>removed POSIX check for str_m &lt; 1; value 0 for str_m is
allowed by ISO C99 (and GNU C library 2.1) (pointed out
on 2000-05-04 by Caol&aacute;n McNamara, caolan@ csn dot ul dot ie).
Besides relaxed license this change in standards adherence
is the main reason to bump up the major version number;
<li>added nonstandard routines asnprintf, vasnprintf, asprintf,
vasprintf that dynamically allocate storage for the
resulting string; these routines are not compiled by default,
see comments where NEED_V?ASN?PRINTF macros are defined;
<li>autoconf contributed by Caol&aacute;n McNamara
</ul>
<dt>2000-10-06 V2.2 Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li><b>BUG FIX</b>: the %c conversion used a temporary variable
that was no longer in scope when referenced,
possibly causing incorrect resulting character;
<li>BUG FIX: make precision and minimal field width unsigned
to handle huge values (2^31 &lt;= n &lt; 2^32) correctly;
also be more careful in the use of signed/unsigned/size_t
internal variables -- probably more careful than many
vendor implementations, but there may still be a case
where huge values of str_m, precision or minimal field
could cause incorrect behaviour;
<li>use separate variables for signed/unsigned arguments,
and for short/int, long, and long long argument lengths
to avoid possible incompatibilities on certain
computer architectures. Also use separate variable
arg_sign to hold sign of a numeric argument,
to make code more transparent;
<li>some fiddling with zero padding and "0x" to make it
Linux compatible;
<li>systematically use macros fast_memcpy and fast_memset
instead of case-by-case hand optimization; determine some
breakeven string lengths for different architectures;
<li>terminology change: <i>format</i> -&gt; <i>conversion specifier</i>,
<i>C9x</i> -&gt; <i>ISO/IEC 9899:1999 ("ISO C99")</i>,
<i>alternative form</i> -&gt; <i>alternate form</i>,
<i>data type modifier</i> -&gt; <i>length modifier</i>;
<li>several comments rephrased and new ones added;
<li>make compiler not complain about 'credits' defined but
not used;
</ul>
</dl>
<h2>Other implementations of snprintf</h2>
<p>I am aware of some other (more or less) portable implementations
of <b>snprintf</b>. I do not claim they are free software - please refer
to their respective copyright and licensing terms.
If you know of other versions please let
<a href="http://www.ijs.si/people/mark/">me</a> know.
<ul>
<li>a very thorough implementation (src/util_snprintf.c)
by the Apache Group distributed with the
<a href="http://www.apache.org/">Apache web server
- http://www.apache.org/</a> .
Does its own floating point conversions using routines
ecvt(3), fcvt(3) and gcvt(3) from the standard C library
or from the GNU libc.
<br>This is from the code:
<blockquote>
This software [...] was originally based
on public domain software written at the
<a href="http://www.ncsa.uiuc.edu/ncsa.html">National Center
for Supercomputing Applications</a>, University of Illinois,
Urbana-Champaign.<br>
[...] This code is based on, and used with the permission of,
the SIO stdio-replacement strx_* functions by Panos Tsirigotis
&lt;<a href="mailto:panos@alumni.cs.colorado.edu">panos@alumni.cs.colorado.edu</a>&gt; for xinetd.
</blockquote>
<li><a href="http://www.qlue.com/downloads/c_utils_README.html">QCI
Utilities</a> use a modified version of snprintf from the Apache group.
<li>implementations as distributed with
<a href="http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/">OpenBSD</a>,
<a href="http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdio/">FreeBSD</a>, and
<a href="http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/basesrc/lib/libc/stdio/">NetBSD</a>
are all wrappers to vfprintf.c, which is derived from software
contributed to Berkeley by Chris Torek.
<li>implementation from Prof. Patrick Powell
&lt;<a href="mailto:papowell@sdsu.edu">papowell@sdsu.edu</a>&gt;,
Dept. Electrical and Computer Engineering, San Diego State University,
San Diego, CA 92182-1309, published in
<a href="http://www.geek-girl.com/bugtraq/1995_3/0217.html">Bugtraq
archives for 3rd quarter (Jul-Aug) 1995</a>.
No floating point conversions.
<li>Brandon Long's
&lt;<a href="mailto:blong@fiction.net">blong@fiction.net</a>&gt;
<a href="http://www.fiction.net/~blong/programs/">modified version</a>
of Prof. Patrick Powell's snprintf with contributions from others.
With minimal floating point support.
<li>implementation (src/snprintf.c) as distributed with
<a href="http://www.sendmail.org/">sendmail - http://www.sendmail.org/</a>
is a cleaned up Prof. Patrick Powell's version
to compile properly and to support .precision and %lx.
<li>implementation from <a href="http://www.csn.ul.ie/~caolan/"
>Caol&aacute;n McNamara</a> available at
<a href="http://www.csn.ul.ie/~caolan/publink/snprintf-1.1.tar.gz"
>http://www.csn.ul.ie/~caolan/publink/snprintf-1.1.tar.gz</a>,
handles floating point.
<li>implementation used by
<a href="ftp://ftp.soscorp.com/pub/sos/lib">newlog</a>
(a replacement for syslog(3)) made available by
the <a href="http://www.soscorp.com">SOS Corporation</a>.
Enabling floating point support is a compile-time option.
<li>implementation by Michael Richardson
&lt;<a href="mailto:mcr@metis.milkyway.com">mcr@metis.milkyway.com</a>&gt;
is available at
<a href="http://sandelman.ottawa.on.ca/SSW/snp/snp.html"
>http://sandelman.ottawa.on.ca/SSW/snp/snp.html</a>.
It is based on BSD44-lite's vfprintf() call, modified to function
on SunOS. Needs internal routines from the 4.4 strtod (included),
requires GCC to compile the long long (aka quad_t) portions.
<li>implementation from Tomi Salo
&lt;<a href="mailto:ttsalo@ssh.fi">ttsalo@ssh.fi</a>&gt;
distributed with
<a href="http://www.Europe.DataFellows.com/f-secure/ssh/">SSH 2.0
Unix Server</a>. Not in public domain.
Floating point conversions done by system's sprintf.
<li>and for completeness: <a href="http://www.ijs.si/people/mark/">my</a>
portable version described in this very document available at
<a href="http://www.ijs.si/software/snprintf/"
>http://www.ijs.si/software/snprintf/</a> .
</ul>
In retrospect, it appears that a lot of effort was wasted by many
people for not being aware of what others are doing. Sigh.
<p>Also of interest:
<a href="http://www.opengroup.org/platform/resolutions/bwg98-006.html"
>The Approved Base Working Group Resolution for XSH5,
Ref: bwg98-006, Topic: snprintf</a>.
<p><hr>
<i><a href="http://www.ijs.si/people/mark/">mm</a></i>
<br>Last updated: 2000-10-18
<p><a href="http://validator.w3.org/check/referer"
><img src="/images/vh40.gif" alt="Valid HTML 4.0!"
border="0" width="88" height="31"></a>
</body>
</html>

File diff suppressed because it is too large Load Diff