RHS 15Nov2004
A sprintf-like command that returns a Tcl_Obj. I use it to do things like:
Tcl_ListObjAppendElement(interp, bcListObj, RHS_MakeStringObj("The offset: %d", pcOffset));
I'm sure there's places in the code that would run into problems when not using gcc, but thats all I use. If people want to improve this, that would be fantastic. Now, for the actual code...
// This is coded specifically for glibc Tcl_Obj * RHS_MakeStringObj(const char *fmt, ...) { /* Guess we need no more than 100 bytes. */ int n, size = 100; char *p; Tcl_Obj *retObj; va_list ap; if ((p = Tcl_Alloc (size)) == NULL) return (Tcl_Obj *)NULL; while (1) { /* Try to print in the allocated space. */ va_start(ap, fmt); n = vsnprintf (p, size, fmt, ap); va_end(ap); /* If that worked, return the string. */ if (n > -1 && n < size) { retObj = Tcl_NewStringObj(p, strlen(p)); Tcl_Free(p); return retObj; } /* Else try again with more space. */ if (n > -1) /* glibc 2.1 */ size = n+1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ if ((p = Tcl_Realloc (p, size)) == NULL) { return (Tcl_Obj *)NULL; } } }
RHS It appears that the microsoft compiler uses the name _vsnprintf rather than vsnprintf. So, if you're using MSVC, you may need to change the name.
From chat:
<patthoyts> In fact, on BSD it looks like you need stdio.h and stdarg.h
MAK Since you mention gcc, I suggest:
#ifndef __GNUC__ # define __attribute__(x) #endif Tcl_Obj * RHS_MakeStringObj(const char *fmt, ...) __attribute__((format(printf, 1, 2)))) ...
This tells gcc that the form of the arguments is the same as a printf and that it should check to make sure that the number of arguments and their types are appropriate given the format string, and issue errors/warnings if not, just as if you mess up a printf() call.