Contents:

    FMTCOMA.TXT     this file
    FMTCOMA.H       the header file
    FMTCOMA.CPP     source code
    FCTEST.CPP      a test progtam.

The programming details are documented in FMTCOMA.H and
FMTCOMA.CPP.


In these days of megabyte files and gigabyte drives it is easy
to forget the user.  There is nothing in the standard C/C++
libraries that will change a nubmer into a string and put
thousands separators into it, and it often isn't done.

Some of us write our own, or find someone else's code.  The
solution is usually a C function, but now we have a problem
with the string buffer.  We cannot make it automatic in the
function, because it disappears before we can use it.  Either
it is passed an external buffer, or it uses a static internal
buffer.  The former means we are responsible for setting by
enough room (quick:  how many bytes do we need to format
LONG_MIN?).  The latter means we can't use it more than once in
the same statement, which can be an inconvenience at times.

In C++ we can use objects, which gets us around both problems.
There is my solution, the class formatComma, which knows how
large to make the buffer, but doesn't use a static one.  We can
also use temporary objects for convenience.

Here's some examples:

    cout <<"This really big file is "
         <<formatComma (big_file_size)
         <<" bytes"
         <<endl;

    sprintf (buffer, "Drive %c: has %s allocated out of %s bytes",
     drive_no +'A',    
     (const char*)formatComma (total_file_size),
     (const char*)formatComma (disk_size));


The class has two constructors, one for signed and the other
for unsigned numbers:

    formatComma (long          n);
    formatComma (unsigned long n);

There are two operators which allow you to read the buffer:

                operator const char* () const;
    const char* operator &           () const;

The first is the standard cast operator.  The second is the
address-of operator, and is not completely kosher.  It returns
the address of the buffer, which is not the same as the address
of the object.  It is used as a shorthand, because doing the
cast (const char*) can clutter up the code.  If for some reason
you need the address of the object you'll have to get rid of
this.

The standard output stream operator is provided as a friend
function:

    friend ostream& operator << (ostream&           ostr,
                                 const formatComma& fc);

The present version handles only long integers, but it can be
extended to other types.  Floating-point numbers are an obvious
one, but they can be tricky.  Not only do you have to worry
about the decimal point (which may not be a period), fractional
parts, and power of ten, but you cannot forget that some are
not numbers at all (infinities, NANs).

A version for 64-bit integers would be useful.  (How long do
you think it will be before drives larger than 4GB are
common?).  Unfortunately, this is not a native type, and there
are few implementations.  MS Windows has a version of this
(variously named int64, __int64, or LONGLONG) but only the DDK
provides the necessary operators for it.

This code has been tested with the Borland compiler 4.51, and
MS Visual C++ 1.52, 2.2, and 4.0.  It works under DOS, Windows
3.1, Windows NT 3.5, and Windows 95.


Jim Howell
February 16, 1996
Compuserve 73547,245

