Version 4 of Useful C Commands For Tcl

Updated 2004-11-16 01:26:32

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.