]> git.sur5r.net Git - cc65/blobdiff - src/common/xsprintf.c
Only for jumps, the lib uses named asm labels in branches
[cc65] / src / common / xsprintf.c
index 307d16e18d32a378811cc541d7e748c76b05a842..a7d26d5ef76ec12c87ee5104976e96826ab0b744 100644 (file)
@@ -1,13 +1,13 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                               xsprintf.c                                 */
+/*                                xsprintf.c                                 */
 /*                                                                           */
-/*                      Replacement sprintf function                        */
+/*                       Replacement sprintf function                        */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
 /* (C) 2000-2004 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
+/*               Roemerstrasse 52                                            */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -42,6 +42,7 @@
 #include "chartype.h"
 #include "check.h"
 #include "inttypes.h"
+#include "strbuf.h"
 #include "va_copy.h"
 #include "xsprintf.h"
 
 
 
 /* The following is a very basic vsnprintf like function called xvsnprintf. It
- * features only the basic format specifiers (especially the floating point
- * stuff is missing), but may be extended if required. Reason for supplying
- * my own implementation is that vsnprintf is standard but not implemented by
- * older compilers, and some that implement it, don't adhere to the standard
- * (for example Microsoft with its _vsnprintf).
- */
+** features only the basic format specifiers (especially the floating point
+** stuff is missing), but may be extended if required. Reason for supplying
+** my own implementation is that vsnprintf is standard but not implemented by
+** older compilers, and some that implement it, don't adhere to the standard
+** (for example Microsoft with its _vsnprintf).
+*/
 
 typedef struct {
 
@@ -72,9 +73,9 @@ typedef struct {
     size_t      BufFill;
 
     /* Argument string buffer and string buffer pointer. The string buffer
-     * must be big enough to hold a converted integer of the largest type
-     * including an optional sign and terminating zero.
-     */
+    ** must be big enough to hold a converted integer of the largest type
+    ** including an optional sign and terminating zero.
+    */
     char        ArgBuf[256];
     int         ArgLen;
 
@@ -206,7 +207,7 @@ static void FormatInt (PrintfCtrl* P, uintmax_t Val)
 
 
     /* Determine the translation table */
-    P->CharTable = (P->Flags & fUpcase)? "0123456789ABCDEF" : "0123456789abcedf";
+    P->CharTable = (P->Flags & fUpcase)? "0123456789ABCDEF" : "0123456789abcdef";
 
     /* Check if the value is negative */
     if ((P->Flags & fUnsigned) == 0 && ((intmax_t) Val) < 0) {
@@ -222,9 +223,9 @@ static void FormatInt (PrintfCtrl* P, uintmax_t Val)
     ToStr (P, Val);
 
     /* The default precision for all integer conversions is one. This means
-     * that the fPrec flag is always set and does not need to be checked
-     * later on.
-     */
+    ** that the fPrec flag is always set and does not need to be checked
+    ** later on.
+    */
     if ((P->Flags & fPrec) == 0) {
         P->Flags |= fPrec;
         P->Prec = 1;
@@ -304,9 +305,9 @@ static void FormatStr (PrintfCtrl* P, const char* Val)
     unsigned WidthPadding;
 
     /* Get the string length limited to the precision. Beware: We cannot use
-     * strlen here, because if a precision is given, the string may not be
-     * zero terminated.
-     */
+    ** strlen here, because if a precision is given, the string may not be
+    ** zero terminated.
+    */
     int Len;
     if ((P->Flags & fPrec) != 0) {
         const char* S = memchr (Val, '\0', P->Prec);
@@ -351,14 +352,14 @@ static void StoreOffset (PrintfCtrl* P)
 /* Store the current output offset (%n format spec) */
 {
     switch (P->LengthMod) {
-        case lmChar:     *va_arg (P->ap, int*)       = P->BufFill;
-        case lmShort:    *va_arg (P->ap, int*)       = P->BufFill;
-        case lmInt:      *va_arg (P->ap, int*)       = P->BufFill;
-        case lmLong:     *va_arg (P->ap, long*)      = P->BufFill;
-        case lmIntMax:   *va_arg (P->ap, intmax_t*)  = P->BufFill;
-        case lmSizeT:    *va_arg (P->ap, size_t*)    = P->BufFill;
-        case lmPtrDiffT: *va_arg (P->ap, ptrdiff_t*) = P->BufFill;
-        default: FAIL ("Invalid size modifier for %n format spec in xvsnprintf");
+        case lmChar:     *va_arg (P->ap, int*)       = P->BufFill; break;
+        case lmShort:    *va_arg (P->ap, int*)       = P->BufFill; break;
+        case lmInt:      *va_arg (P->ap, int*)       = P->BufFill; break;
+        case lmLong:     *va_arg (P->ap, long*)      = P->BufFill; break;
+        case lmIntMax:   *va_arg (P->ap, intmax_t*)  = P->BufFill; break;
+        case lmSizeT:    *va_arg (P->ap, size_t*)    = P->BufFill; break;
+        case lmPtrDiffT: *va_arg (P->ap, ptrdiff_t*) = P->BufFill; break;
+        default: FAIL ("Invalid size modifier for %n format spec. in xvsnprintf()");
     }
 }
 
@@ -366,14 +367,15 @@ static void StoreOffset (PrintfCtrl* P)
 
 int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap)
 /* A basic vsnprintf implementation. Does currently only support integer
- * formats.
- */
+** formats.
+*/
 {
     PrintfCtrl P;
     int Done;
     char F;
     char SBuf[2];
     const char* SPtr;
+    int UseStrBuf = 0;
 
 
     /* Initialize the control structure */
@@ -416,8 +418,8 @@ int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap)
         if (F == '*') {
             P.Width = va_arg (P.ap, int);
             /* A negative field width argument is taken as a - flag followed
-             * by a positive field width.
-             */
+            ** by a positive field width.
+            */
             if (P.Width < 0) {
                 P.Flags |= fMinus;
                 P.Width = -P.Width;
@@ -443,8 +445,8 @@ int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap)
             if (F == '*') {
                 P.Prec = va_arg (P.ap, int);
                 /* A negative precision argument is taken as if the precision
-                 * were omitted.
-                 */
+                ** were omitted.
+                */
                 if (P.Prec < 0) {
                     P.Flags &= ~fPrec;
                 }
@@ -460,8 +462,8 @@ int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap)
                 }
             } else if (F == '-') {
                 /* A negative precision argument is taken as if the precision
-                 * were omitted.
-                 */
+                ** were omitted.
+                */
                 F = *Format++;          /* Skip the minus */
                 while (IsDigit (F = *Format++)) ;
                 P.Flags &= ~fPrec;
@@ -571,11 +573,38 @@ int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap)
                 break;
 
             case 'p':
-                /* Use hex format for pointers */
-                P.Flags |= (fUnsigned | fPrec);
-                P.Prec = ((sizeof (void*) * CHAR_BIT) + 3) / 4;
-                P.Base = 16;
-                FormatInt (&P, (uintptr_t) va_arg (P.ap, void*));
+                /* See comment at top of header file */
+                if (UseStrBuf) {
+                    /* Argument is StrBuf */
+                    const StrBuf* S = va_arg (P.ap, const StrBuf*);
+                    CHECK (S != 0);
+                    /* Handle the length by using a precision */
+                    if ((P.Flags & fPrec) != 0) {
+                        /* Precision already specified, use length of string 
+                        ** if less.
+                        */
+                        if ((unsigned) P.Prec > SB_GetLen (S)) {
+                            P.Prec = SB_GetLen (S);
+                        }
+                    } else {
+                        /* No precision, add it */
+                        P.Flags |= fPrec;
+                        P.Prec  = SB_GetLen (S);
+                    }
+                    FormatStr (&P, SB_GetConstBuf (S));
+                    UseStrBuf = 0;              /* Reset flag */
+                } else {
+                    /* Use hex format for pointers */
+                    P.Flags |= (fUnsigned | fPrec);
+                    P.Prec = ((sizeof (void*) * CHAR_BIT) + 3) / 4;
+                    P.Base = 16;
+                    FormatInt (&P, (uintptr_t) va_arg (P.ap, void*));
+                }
+                break;
+
+            case 'm':
+                /* See comment at top of header file */
+                UseStrBuf = 1;
                 break;
 
             case 'n':
@@ -593,9 +622,9 @@ int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap)
     va_end (P.ap);
 
     /* Terminate the output string and return the number of chars that had
-     * been written if the buffer was large enough.
-     * Beware: The terminating zero is not counted for the function result!
-     */
+    ** been written if the buffer was large enough.
+    ** Beware: The terminating zero is not counted for the function result!
+    */
     AddChar (&P, '\0');
     return P.BufFill - 1;
 }
@@ -604,8 +633,8 @@ int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap)
 
 int xsnprintf (char* Buf, size_t Size, const char* Format, ...)
 /* A basic snprintf implementation. Does currently only support integer
- * formats.
- */
+** formats.
+*/
 {
     int Res;
     va_list ap;
@@ -620,7 +649,7 @@ int xsnprintf (char* Buf, size_t Size, const char* Format, ...)
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
@@ -647,6 +676,3 @@ int xvsprintf (char* Buf, size_t BufSize, const char* Format, va_list ap)
     CHECK (Res >= 0 && (unsigned) (Res+1) < BufSize);
     return Res;
 }
-
-
-