LCOV - code coverage report
Current view: top level - mozglue/misc - Printf.h (source / functions) Hit Total Coverage
Test: output.info Lines: 50 54 92.6 %
Date: 2017-07-14 16:53:18 Functions: 18 24 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* Printf-like functions, with canned variants that malloc their result.  */
       8             : 
       9             : #ifndef mozilla_Printf_h
      10             : #define mozilla_Printf_h
      11             : 
      12             : /*
      13             : ** API for PR printf like routines.
      14             : **
      15             : ** These exist partly for historical reasons -- initially they were in
      16             : ** NSPR, then forked in tree and modified in js/ -- but now the prime
      17             : ** motivation is both closer control over the exact formatting (with
      18             : ** one exception, see below) and also the ability to control where
      19             : ** exactly the generated results are sent.
      20             : **
      21             : ** It might seem that this could all be dispensed with in favor of a
      22             : ** wrapper around |vsnprintf| -- except that this implementation
      23             : ** guarantees that the %s format will accept a NULL pointer, whereas
      24             : ** with standard functions this is undefined.
      25             : **
      26             : ** This supports the following formats.  It implements a subset of the
      27             : ** standard formats; due to the use of MOZ_FORMAT_PRINTF, it is not
      28             : ** permissible to extend the standard, aside from relaxing undefined
      29             : ** behavior.
      30             : **
      31             : **      %d - decimal
      32             : **      %u - unsigned decimal
      33             : **      %x - unsigned hex
      34             : **      %X - unsigned uppercase hex
      35             : **      %o - unsigned octal
      36             : **      %hd, %hu, %hx, %hX, %ho - "short" versions of above
      37             : **      %ld, %lu, %lx, %lX, %lo - "long" versions of above
      38             : **      %lld, %llu, %llx, %llX, %llo - "long long" versions of above
      39             : **      %zd, %zo, %zu, %zx, %zX - size_t versions of above
      40             : **      %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat)
      41             : **           You should use PRI*SIZE macros instead
      42             : **      %s - string
      43             : **      %S, %ls - wide string, that is wchar_t*
      44             : **      %c - character
      45             : **      %p - pointer (deals with machine dependent pointer size)
      46             : **      %f - float; note that this is actually formatted using the
      47             : **           system's native printf, and so the results may vary
      48             : **      %g - float; note that this is actually formatted using the
      49             : **           system's native printf, and so the results may vary
      50             : */
      51             : 
      52             : #include "mozilla/AllocPolicy.h"
      53             : #include "mozilla/Assertions.h"
      54             : #include "mozilla/Attributes.h"
      55             : #include "mozilla/IntegerPrintfMacros.h"
      56             : #include "mozilla/SizePrintfMacros.h"
      57             : #include "mozilla/Types.h"
      58             : #include "mozilla/UniquePtr.h"
      59             : 
      60             : #include <stdarg.h>
      61             : #include <string.h>
      62             : 
      63             : namespace mozilla {
      64             : 
      65             : /*
      66             :  * This class may be subclassed to provide a way to get the output of
      67             :  * a printf-like call, as the output is generated.
      68             :  */
      69             : class PrintfTarget
      70             : {
      71             : public:
      72             :     /* The Printf-like interface.  */
      73             :     bool MFBT_API print(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3);
      74             : 
      75             :     /* The Vprintf-like interface.  */
      76             :     bool MFBT_API vprint(const char* format, va_list) MOZ_FORMAT_PRINTF(2, 0);
      77             : 
      78             : protected:
      79             :     MFBT_API PrintfTarget();
      80        9146 :     virtual ~PrintfTarget() { }
      81             : 
      82             :     /* Subclasses override this.  It is called when more output is
      83             :        available.  It may be called with len==0.  This should return
      84             :        true on success, or false on failure.  */
      85             :     virtual bool append(const char* sp, size_t len) = 0;
      86             : 
      87             : private:
      88             : 
      89             :     /* Number of bytes emitted so far.  */
      90             :     size_t mEmitted;
      91             : 
      92             :     /* The implementation calls this to emit bytes and update
      93             :        mEmitted.  */
      94       63730 :     bool emit(const char* sp, size_t len) {
      95       63730 :         mEmitted += len;
      96       63730 :         return append(sp, len);
      97             :     }
      98             : 
      99             :     bool fill2(const char* src, int srclen, int width, int flags);
     100             :     bool fill_n(const char* src, int srclen, int width, int prec, int type, int flags);
     101             :     bool cvt_l(long num, int width, int prec, int radix, int type, int flags, const char* hxp);
     102             :     bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags, const char* hexp);
     103             :     bool cvt_f(double d, const char* fmt0, const char* fmt1);
     104             :     bool cvt_s(const char* s, int width, int prec, int flags);
     105             : };
     106             : 
     107             : namespace detail {
     108             : 
     109             : template<typename AllocPolicy = mozilla::MallocAllocPolicy>
     110             : struct AllocPolicyBasedFreePolicy
     111             : {
     112           5 :   void operator()(const void* ptr) {
     113             :     AllocPolicy policy;
     114           5 :     policy.free_(const_cast<void*>(ptr));
     115           5 :   }
     116             : };
     117             : 
     118             : }
     119             : 
     120             : // The type returned by Smprintf and friends.
     121             : template<typename AllocPolicy>
     122             : using SmprintfPolicyPointer = mozilla::UniquePtr<char, detail::AllocPolicyBasedFreePolicy<AllocPolicy>>;
     123             : 
     124             : // The default type if no alloc policy is specified.
     125             : typedef SmprintfPolicyPointer<mozilla::MallocAllocPolicy> SmprintfPointer;
     126             : 
     127             : // Used in the implementation of Smprintf et al.
     128             : template<typename AllocPolicy>
     129             : class MOZ_STACK_CLASS SprintfState final : private mozilla::PrintfTarget, private AllocPolicy
     130             : {
     131             :  public:
     132        8274 :     explicit SprintfState(char* base)
     133             :         : mMaxlen(base ? strlen(base) : 0)
     134             :         , mBase(base)
     135        8274 :         , mCur(base ? base + mMaxlen : 0)
     136             :     {
     137        8273 :     }
     138             : 
     139        8274 :     ~SprintfState() {
     140        8274 :         this->free_(mBase);
     141       16548 :     }
     142             : 
     143        8273 :     bool vprint(const char* format, va_list ap_list) MOZ_FORMAT_PRINTF(2, 0) {
     144             :         // The "" here has a single \0 character, which is what we're
     145             :         // trying to append.
     146        8273 :         return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1);
     147             :     }
     148             : 
     149        8274 :     SmprintfPolicyPointer<AllocPolicy> release() {
     150        8274 :         SmprintfPolicyPointer<AllocPolicy> result(mBase);
     151        8274 :         mBase = nullptr;
     152        8274 :         return result;
     153             :     }
     154             : 
     155             :  protected:
     156             : 
     157       65955 :     bool append(const char* sp, size_t len) override {
     158             :         ptrdiff_t off;
     159             :         char* newbase;
     160             :         size_t newlen;
     161             : 
     162       65955 :         off = mCur - mBase;
     163       65955 :         if (off + len >= mMaxlen) {
     164             :             /* Grow the buffer */
     165       14258 :             newlen = mMaxlen + ((len > 32) ? len : 32);
     166       14258 :             newbase = static_cast<char*>(this->maybe_pod_realloc(mBase, mMaxlen, newlen));
     167       14258 :             if (!newbase) {
     168             :                 /* Ran out of memory */
     169           0 :                 return false;
     170             :             }
     171       14258 :             mBase = newbase;
     172       14258 :             mMaxlen = newlen;
     173       14258 :             mCur = mBase + off;
     174             :         }
     175             : 
     176             :         /* Copy data */
     177       65955 :         memcpy(mCur, sp, len);
     178       65955 :         mCur += len;
     179       65955 :         MOZ_ASSERT(size_t(mCur - mBase) <= mMaxlen);
     180       65955 :         return true;
     181             :     }
     182             : 
     183             :  private:
     184             : 
     185             :     size_t mMaxlen;
     186             :     char* mBase;
     187             :     char* mCur;
     188             : };
     189             : 
     190             : /*
     191             : ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
     192             : ** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release
     193             : ** the memory returned.
     194             : */
     195             : template<typename AllocPolicy = mozilla::MallocAllocPolicy>
     196             : MOZ_FORMAT_PRINTF(1, 2)
     197           3 : SmprintfPolicyPointer<AllocPolicy> Smprintf(const char* fmt, ...)
     198             : {
     199           6 :     SprintfState<AllocPolicy> ss(nullptr);
     200             :     va_list ap;
     201           3 :     va_start(ap, fmt);
     202           3 :     bool r = ss.vprint(fmt, ap);
     203           3 :     va_end(ap);
     204           3 :     if (!r) {
     205           0 :         return nullptr;
     206             :     }
     207           3 :     return ss.release();
     208             : }
     209             : 
     210             : /*
     211             : ** "append" sprintf into a malloc'd buffer. "last" is the last value of
     212             : ** the malloc'd buffer. sprintf will append data to the end of last,
     213             : ** growing it as necessary using realloc. If last is nullptr, SmprintfAppend
     214             : ** will allocate the initial string. The return value is the new value of
     215             : ** last for subsequent calls, or nullptr if there is a malloc failure.
     216             : */
     217             : template<typename AllocPolicy = mozilla::MallocAllocPolicy>
     218             : MOZ_FORMAT_PRINTF(2, 3)
     219             : SmprintfPolicyPointer<AllocPolicy> SmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last,
     220             :                                                   const char* fmt, ...)
     221             : {
     222             :     SprintfState<AllocPolicy> ss(last.release());
     223             :     va_list ap;
     224             :     va_start(ap, fmt);
     225             :     bool r = ss.vprint(fmt, ap);
     226             :     va_end(ap);
     227             :     if (!r) {
     228             :         return nullptr;
     229             :     }
     230             :     return ss.release();
     231             : }
     232             : 
     233             : /*
     234             : ** va_list forms of the above.
     235             : */
     236             : template<typename AllocPolicy = mozilla::MallocAllocPolicy>
     237             : MOZ_FORMAT_PRINTF(1, 0)
     238        8264 : SmprintfPolicyPointer<AllocPolicy> Vsmprintf(const char* fmt, va_list ap)
     239             : {
     240       16528 :     SprintfState<AllocPolicy> ss(nullptr);
     241        8263 :     if (!ss.vprint(fmt, ap))
     242           0 :         return nullptr;
     243        8264 :     return ss.release();
     244             : }
     245             : 
     246             : template<typename AllocPolicy = mozilla::MallocAllocPolicy>
     247             : MOZ_FORMAT_PRINTF(2, 0)
     248           7 : SmprintfPolicyPointer<AllocPolicy> VsmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last,
     249             :                                                    const char* fmt, va_list ap)
     250             : {
     251          14 :     SprintfState<AllocPolicy> ss(last.release());
     252           7 :     if (!ss.vprint(fmt, ap))
     253           0 :         return nullptr;
     254           7 :     return ss.release();
     255             : }
     256             : 
     257             : /*
     258             : ** Free the memory allocated, for the caller, by Smprintf.
     259             : */
     260             : template<typename AllocPolicy = mozilla::MallocAllocPolicy>
     261        3956 : void SmprintfFree(char* mem)
     262             : {
     263             :     AllocPolicy allocator;
     264        3956 :     allocator.free_(mem);
     265        3956 : }
     266             : 
     267             : } // namespace mozilla
     268             : 
     269             : #endif /* mozilla_Printf_h */

Generated by: LCOV version 1.13