Unified CMarkup for STL and MFC

As of CMarkup release 9.0, CMarkup can be compiled for either MFC or STL strings (prior to 9.0, the CMarkupSTL class was separate from CMarkup). The primary result of merging these classes has been a lot more functionality for the STL version including UNICODE support and text encoding conversion functions.

Update September 27, 2008: With CMarkup release 10.0 things have gotten even simpler. For Visual C++ users, CMarkup no longer depends on tchar.h, and for others, CMarkup defaults to MARKUP_STL.

CMarkupSTL customers who are upgrading from versions earlier than 9.0 should do the following:

  • change places where you use the "CMarkupSTL" class name to "CMarkup"
  • include Markup.cpp and Markup.h in the project instead of MarkupSTL.cpp and MarkupSTL.h
  • if you are using Visual C++, put MARKUP_STL in your project compiler defines
  • The free Express edition of Microsoft Visual Studio 2005 does not include MFC or plain C++/Win32 Windows programming (Express only supports .NET and console apps), but it does include Microsoft's best STL support yet.

    CMarkup for STL strings has been tested in Visual C++ 2005 and 2008 Express, OSX XCode 2.3, and the free Dev-C++ IDE Mingw compiler 2.95.

    See also: CMarkup STL Platforms.

    Pre-compiled headers in Visual Studio

    Markup.cpp no longer calls #include "stdafx.h" which was specifically done for Visual Studio before CMarkup release 9.0. This means that now in Visual Studio, whether you are using MFC or STL, you must go into the project file precompiled headers settings for Markup.cpp and specify "not using" precompiled headers.

    See also: Pre-compiled Header Issue.

    Platform differences

    Depending on your platform, compiler and build options there are some differences in the way CMarkup operates behind the scenes. One important option affects the text encoding used:

  • string encoding: UTF-8 (no define), ANSI (define MBCS) or wide char (define UNICODE)
  • Three other options are only a choice in VC++:

  • string class: MFC CString or the standard C++ STL string (define MARKUP_STL)
  • Windows Text Conversion: Win API or standard C++ conversions. (define MARKUP_STDCONV)
  • MSVC safe strings: standard or VC++ 2005 safe functions. (define MARKUP_SAFESTR)
  • Standard C++ character conversion (MARKUP_STDCONV) to and from system/user locale character sets (ANSI/DBCS) depends on setlocale. See non-Unicode text handling in CMarkup.

    In release 9.0 the MARKUP_STDC define forced VC++ builds not to include tchar.h, but that has been completely removed in release 10.0.

    Text defines

    The unified CMarkup class isolates all the string and text differences into a series of MCD_ defines in the Markup.h header file. This allows you to control the way it is compiled on different platforms, and increases your build options. It even potentially shows you what would be required to use another string class instead of STL or MFC string classes!

    Markup.h comes with text settings for UNICODE and non-UNICODE (i.e. either UTF-8 or MBCS).

    Default Text Defines
    Define UTF-8 or MBCS UNICODE
    MCD_CHAR char wchar_t
    MCD_PCSZ const char* const wchar_t*
    MCD_PSZCPY strcpy wcscpy
    MCD_PSZLEN (int)strlen (int)wcslen
    MCD_PSZCHR strchr wcschr
    MCD_PSZSTR strstr wcsstr
    MCD_PSZNCPY strncpy wcsncpy
    MCD_PSZTOL strtol wcstol
    MCD_PSZNCMP strncmp wcsncmp
    MCD_SPRINTF sprintf swprintf
    MCD_FOPEN fopen _wfopen
    MCD_STRERROR strerror(errno) or undefined* wcserror(errno)
    MCD_T(s) s L s
    MCD_CLEN(p) 1 or mb function* 1

    *If MCD_STRERROR is not defined (Windows CE doesn't have it), CMarkup calls the Win32 FormatMessage (see Markup.cpp).

    *MCD_CLEN in an MBCS build uses either _mbclen in VC++ without MARKUP_STDCONV defined or else mblen.

    String defines

    Markup.h comes with string settings for MFC and STL. To use STL in Visual C++ you must define MARKUP_STL, otherwise VC++ defaults to MFC, while other compilers default to STL.

    Default String Defines
    Define MFC STL
    MCD_STR CString std::string or
    std::wstring
    MCD_2PCSZ(s) ((MCD_PCSZ)s) s.c_str()
    MCD_STRLENGTH(s) s.GetLength() (int)s.size()
    MCD_STRCLEAR(s) s.Empty() s.erase()
    MCD_STRISEMPTY(s) s.IsEmpty() s.empty()
    MCD_STRMID(s,n,l) s.Mid(n,l) s.substr(n,l)
    MCD_STRASSIGN(s,p,n) s=CString(p,n) s.assign(p,n)
    MCD_STRCAPACITY(s) (((CStringData*)((MCD_PCSZ)s)-1)
    ->nAllocLength)
    (int)s.capacity()
    MCD_STRINSERTREPLACE(d,i,r,s) d.replace(i,r,s)
    MCD_GETBUFFER(s,n) s.GetBuffer(n) new MCD_CHAR[n+1]
    MCD_RELEASEBUFFER(s,p,n) s.ReleaseBuffer(n) s.assign(p,n); delete[]p
    MCD_BLDRESERVE(s,n) MCD_CHAR*pD=s.GetBuffer(n);
    int nL=0
    s.reserve(n)
    MCD_BLDCHECK(s,n,d) if(nL+d>n){
    s.ReleaseBuffer(nL);
    n<<=2;
    pD=s.GetBuffer(n);}
    MCD_BLDRELEASE(s) s.ReleaseBuffer(nL)
    MCD_BLDAPPENDN(s,p,n) MCD_PSZNCPY(&pD[nL],p,n);nL+=n s.append(p,n)
    MCD_BLDAPPEND(s,p) MCD_PSZCPY(&pD[nL],p);
    nL+=MCD_PSZLEN(p)
    s.append(p)
    MCD_BLDAPPEND1(s,c) pD[nL++]=(MCD_CHAR)(c) s+=(MCD_CHAR)(c)

    In the case where MFC MCD_STRINSERTREPLACE is not defined (CString doesn't have it), CMarkup uses MCD_GETBUFFER and MCD_RELEASEBUFFER with a memmove/memcpy implementation (see Markup.cpp).