TweetFollow Us on Twitter

Stream for All Seasons

Volume Number: 16 (2000)
Issue Number: 4
Column Tag: Programming

A Stream for All Seasons

by Neil Mayhew, Calgary, AB

A lightweight ostream-compatible class using Pascal strings

Getting Your Message Across

They say a picture is worth a thousand words, but a picture without any words is often hard to figure out. The Macintosh user interface does a wonderful job of being graphical, but it also uses text very effectively in appropriate places.

Can you imagine using a large application without a single word of text on its menus and dialogs? Consumer electronics devices that use cute little icons for everything can be extremely puzzling until you have spent a little time studying the manual-in text form, of course.

The ability to manipulate text is therefore crucial to even the most graphical Macintosh program. Text in the user-interface-rather than text as data-uses Pascal string conventions. This doesn't always fit very well with C, which has it's own string conventions. The problem is worse with C++, which has a much richer standard library of text manipulation functions-none of which understand the Pascal string format.

However, the power and flexibility of C++ can be used to overcome many of these limitations in a way that is both transparent and economical. Yet again, templates, inline functions, and stack-based objects can come to our rescue-if we know how to take advantage of them.

This month's article describes a lightweight class that builds Pascal strings using the << notation used by the standard C++ ostream. Next month, I'll introduce a program that uses STL-compatible iterators to monitor your System Folder for unexpected changes to extensions and control panels by wayward installer programs.

Printf Considered Harmful

Much of the time, text that is being displayed in the user-interface is a fixed string taken from a resource. Sometimes, though, text is built up from a number of pieces, some fixed and some not. We have come to appreciate having the text of the Undo menu item change to reflect the action that is being undone. In fact, there are all kinds of situations in which user-interface text needs to be built up programmatically: prompts, error messages, status messages, progress messages, and so on. In all of these cases, the generated text needs to be inserted into the user-interface as a Pascal string.

There are a number of simple approaches to doing this. For alerts and dialogs, the ParamText mechanism is useful. Or, a sequence of string-concatenation operations can be performed. Even better, one of the printf family of functions can be used to format a string with complex substitutions via % characters.

Although the printf approach is powerful, it has some severe limitations in any setting:

  • substitutions are not type-checked or counted, and are therefore error-prone
  • sprintf's output string is not protected against overflow

In a Mac OS setting, there are some additional limitations:

  • Pascal strings are not understood as arguments
  • the output is a C string rather than a Pascal string
  • printf cannot be used at interrupt time or in a code resource
  • the C i/o library increases code size considerably

The C++ iostream library takes care of the first two problems very effectively, using ostringstream, but the Mac OS-specific problems remain. How could we retain the elegant << syntax and yet be able to handle Pascal strings with very low overheads?

Simple Is Beautiful

Early on in my programming career, I learnt that writing large, complicated programs is relatively easy. What is hard is keeping them simple! A more experienced colleague had a wonderful knack for developing small, sophisticated programs that contained just enough functionality for the task in hand-and no more. The C++ iostreams library quite rightly has a huge range of functionality, much of which we do not need for our limited task of formatting strings. If we select just the functionality that is useful to us-concatenating strings, integers and floating-point numbers-it should not be hard to implement a lightweight class that supports << syntax for those items.

The output needs to be a Pascal string, and various manipulation capabilities for Pascal strings will be needed. It makes sense therefore first to develop a C++ encapsulation of Pascal strings. This will simplify our stream implementation, and will be a useful facility in itself.

As I mentioned in last month's article, the constant template-argument feature of C++ is specifically aimed at the implementation of fixed-length arrays such as Pascal strings. This enables us to store various sizes of strings on the stack, instead of having to allocate variable-length blocks from the heap. Without this, we would not be able to meet our design criterion of usability at interrupt time or in a code resource.

Making It To First Base

Last month's template used only inline functions, and these were sufficiently simple that they more or less disappeared in the generated code. The functions to process strings are not so simple, however. If we make them inline, we face two possible outcomes: either a substantial chunk of code will be inserted into every routine that calls one of our template's methods, or the compiler will opt to make them non-inline anyway.

What happens if we have non-inline methods in a template class? Ordinarily, we would put the implementation of non-inline methods into a .cp file that is compiled and linked. However, most development environments (CodeWarrior included) are not able to handle template methods this way. A separate copy of the method needs to be generated for each set of template arguments that are used with its class, and the compiler can't know which copies to generate until it has compiled the whole project. This restriction is normally overcome by putting the implementation of the method into the header file, but not declaring it inline. The compiler generates 'real' code for each combination of template arguments, and the linker takes care of eliminating redundant copies.

In a large project, this can slow build times by an order of magnitude. This is especially unfortunate when the majority of the copies generate almost identical machine code. For example, in the case of our Pascal string class, this would mean a separate copy of the code for each different string size (31, 63, 255, etc.) even though all the copies are performing virtually the same operation. This effect is known as code bloat.

If the foregoing paragraphs haven't made much sense to you, Don't Panic! Just remember that code bloat is something you definitely want to avoid. However, this doesn't mean that you have to stay clear of templates altogether. There is a very simple solution.

If you find that the majority of your template's methods are going to generate virtually identical code, then they are not really part of the template at all. Why not put them into a non-template class and have your template call them using very simple inline methods? The easiest way to do this is by having your template inherit from a non-template class that contains most of the actual code. This technique is known as a template class with a non-template base, and is sufficient to cure most kinds of code bloat. There are other solutions for the more difficult cases, but we won't go into those here. If you are interested, try looking up explicit instantiation and partial specialization in any good C++ book.

A Solid Foundation

The algorithms to copy, append and compare Pascal strings are the same regardless of the buffer length. The first step in building our C++ encapsulation is therefore to define a non-template base class that implements this functionality. We could of course simply use global functions, but by including them in the class, we can give them shorter, simpler names. We also don't have to worry whether they provide behavior that would be needed when used from outside the class, such as returning an error on overflow.

The class declaration looks like this:

class PascalStringBase {
protected:
	typedef unsigned char uchar;
	static void assign(int max, uchar* dst, const uchar*);
	static void assign(int max, uchar* dst, const char*);
	static void append(int max, uchar* dst, const uchar*);
	static void append(int max, uchar* dst, const char*);
	static void append(int max, uchar* dst, uchar);
	static void append(int max, uchar* dst, char);
	static int  compare(const uchar*, const uchar*);
	static int  compare(const uchar*, const char*);
	static bool equal(const uchar*, const uchar*);
	static bool equal(const uchar*, const char*);
};

Note that it is possible to pass in both C and Pascal strings for assignment, concatenation and comparison. This is done by overloading the function names to handle both signed and unsigned string pointers. We also haven't arranged to return any error codes, as we are not interested in checking for error codes whilst building strings. Therefore the assign and append functions silently truncate the destination string if overflow occurs.

There is a good reason why all these functions are declared static. The string buffer, referred to in these functions by the dst pointer, has to be a part of the template, since the length will be a template argument. The buffer address must therefore be passed as one of the arguments, along with its length. Since these methods do not refer to any data members (instance variables), they are independent of any instance of the class and they should properly be made static. In the same way, no constructors or destructor are necessary since there is nothing to initialize or release.

The implementation of PascalStringBase is not very interesting, so we won't include it here. It defines a local version of strlen to help with the C strings, and it uses BlockMoveData for copying data around. I opted to use RelString and CompareString for the Pascal comparisons, but this would need to be changed if the code was ever going to be used from an interrupt routine. The other methods could also have used standard Toolbox or glue functions, but overflow management would still have been necessary.

Dressing It Up

Armed with this low-level functionality, we can define a clean, efficient C++ encapsulation of Pascal strings:

template<unsigned char max>
class PascalString : public PascalStringBase {

protected:
	uchar data[max + 1];

public:
	PascalString()
			{ clear(); }
	PascalString(const PascalString& p)
			{ *this = p; } // Calls operator =
	PascalString(const uchar* p)
			{ *this = p; } // Calls operator =
	PascalString(const char* p)
			{ *this = p; } // Calls operator =

	PascalString& clear()
			{ data[0] = 0; return *this; }
	
	// Assignment
	PascalString& operator = (const PascalString& p)
			{ assign(max, data, p); return *this; }
	PascalString& operator = (const uchar* p)	
			{ assign(max, data, p); return *this; }
	PascalString& operator = (const char* p)
			{ assign(max, data, p); return *this; }

	// Concatenation
	PascalString& operator += (const uchar* p)
			{ append(max, data, p); return *this; }
	PascalString& operator += (const char* p)
			{ append(max, data, p); return *this; }

	PascalString& operator += (uchar c)
			{ append(max, data, c); return *this; }
	PascalString& operator += (char c)
			{ append(max, data, c); return *this; }
	
	// Comparison
	bool operator <  (const uchar* p) const
			{ return compare(data, p) < 0; }
	bool operator <  (const char* p) const
			{ return compare(data, p) < 0; }
	bool operator == (const uchar* p) const
			{ return equal(data, p); }
	bool operator == (const char* p) const
			{ return equal(data, p); }

	// Conversion operator
	operator const uchar * () const { return data; }
	
	// Information
	uchar length()  const { return data[0]; }
	uchar maximum() const { return max; }
};

All of the methods are trivial wrappers for the 'worker' functions from the base class. Yet, the constant template argument max takes care of the ugly details of buffer allocation and length checking. objects of any size can be defined as stack variables, and take up no more space than the data itself. In fact, because the memory layout of the object is the same as the equivalent raw Pascal string, an unsigned char* can be cast to a PascalString<nnn>* that is used without restriction. A static inline method that performs such a cast would be a useful addition.

Note that because we have declared max as an unsigned char, the compiler will ensure that its value is within the correct range.

PascalString explicitly defines three of the fundamental four methods that always need to be considered when designing a class.

  • The default constructor (no arguments) is necessary to ensure that the default value of a PascalString is a zero-length string.
  • If the copy constructor (const PascalString&) is not explicitly defined, the compiler will supply an automatic version which copies every byte of the entire object. For larger values of max, and short strings, this is undesirable. Like the others, this constructor delegates the work to the equivalent assignment operator. No prior initialization is needed, since any previous state is ignored by PascalString's assignment operators.
  • The compiler will also supply a default assignment operator if one is not explicitly defined. Again, this would copy the entire object in every case. We already have an assign function that takes a const unsigned char*, so we make implicit use of the conversion operator and call this function to perform the copy.
  • The destructor is the only one of the four that is not defined, since there is no cleanup needed when a PascalString is destroyed.

The conversion operator allows a PascalString to be used in any context that requires a raw Pascal string. It implicitly converts a PascalString to a const unsigned char*. However, since this gives up any control of overflow checking, the pointer has to be const to prevent modification of the internal data. If max is 255, it is always safe to pass a writable pointer to the internal data, but there is no simple way to arrange for this to happen automatically for just this value of max. A compromise would be to define a method that takes a size as an argument, returns a writable pointer to the data if the size is less than or equal to max, and returns nil otherwise. This would allow a PascalString to be passed as a receive-buffer to Toolbox routines without the need for casting.

A more radical solution would be to fool around with MacTypes.h to redefine Str31 as PascalString<31>* and so on, so that the Mac OS APIs appear to be expecting instances of our template class instead of raw pointers. Since the pointer value that is passed is the same, the APIs will work as expected, but the API arguments will automatically be checked for correctness of length. It would be more correct, but more work, to write inline wrapper functions for all the APIs that take writable Pascal strings as arguments. These would simply perform a suitable cast on their PascalString& argument and pass the result on to the OS. The API name could be retained if the wrappers were placed in a different namespace.

Heading For The Goal

Our main goal is the creation of a stream class. This is not hard now that we have the needed PascalString class.

It doesn't make much sense to build a stream on anything less than a PascalString<255>, so our stream class doesn't need to be a template since we don't need to specify a size. C++ does allow us to specify default values for template arguments, so we could make it a template with a default size of 255. However, this would start another round in the fight against code bloat, and there is no need for this additional complication. Remember, simple is beautiful!

We now have the interesting phenomenon of a class inheriting from a template inheriting from a class:

class PascalStringStream : public PascalString<255>
{
public:
	// Concatenation
	PascalStringStream& operator << (const unsigned char* s)
			{ return *this += s; }
	PascalStringStream& operator << (const char* s)
			{ return *this += s; }
	PascalStringStream& operator << (unsigned char c)
			{ return *this += c; }
	PascalStringStream& operator << (char c)
			{ return *this += c; }

	// Numbers
	PascalStringStream& operator << (long);
	PascalStringStream& operator << (double);

	// Convenience
	const unsigned char* contents() const { return *this; }
	PascalStringStream&  reset() { clear(); return *this; }
};

It makes sense to use inheritance rather than aggregation (embedding PascalString as a data member), since we want our stream to be more or less interchangeable with a PascalString. It also saves us the effort of redeclaring several methods. However, using aggregation also works quite well.

We have chosen not to implement advanced features such as field-widths and justification. This is very rarely appropriate in a GUI context with proportional-width fonts, and we want to keep the size and complexity to a minimum.

Why create an extra class?

The concatenation methods are just re-presentations of the ones from PascalString, using a different operator. Why bother with this? Because the associativity of << is different from +=, so that it becomes possible to 'cascade' a series of concatenations in typical ostream style:

s << "\pOverwrite " << oldf << "\p with " << newf << "\p?"

In which case, why not just put all this functionality into PascalString? Because accidental use of some of PascalStringStream's operators may bring surprises. For example, if we accidentally pass an int instead of a char to a concatenation operation on a string, do we want a decimal representation appended to the end of a string? A warning from the compiler would be preferable. By requiring us to include stream functionality explicitly, through our choice of class, these ambiguities are avoided.

There is another advantage to using the << operator. Every expression that uses a PascalStringStream is upwardly compatible with the standard C++ ostream. If, for example, you write some utility code that dumps out parameters from OpenTransport, that code will work equally well with either type of stream. If you later decide to send the output to a file rather than to a dialog, you only need to change the stream declaration and everything will work as expected. If the formatting capabilities of PascalStringStream turn out to be too simple, you can move up to using an ostringstream without a problem.

It is even possible to place your text-generating code inside a template function (not a template class), so that it will work with any type of stream you choose to pass to it. Just prefix the function or method definition with template<class Stream> and use Stream wherever you need to declare a stream as a variable or an argument. The compiler can infer the template argument from the function arguments, so you can still call the function as if it were a non-template one.

Internal details

There are only two methods that are not trivial and inline. These are implemented in a .cp file. The details are not very interesting, but for completeness, we'll include them here. They each create a text representation of the number in a buffer on the stack, and append it to the main string.

#include <fp.h>		// Mac OS APIs for manipulating floating-point numbers

// Decimal integer output

PascalStringStream&
		PascalStringStream::operator << (long n)
{
	Str31 num;
	NumToString(n, num);
	return *this << num;
}

// Quick-and-easy floating-point output: X.XXXXXe±Y

const int precision	=  6;

PascalStringStream&
		PascalStringStream::operator << (double d)
{
	decform form;
	decimal result;
	char output[DECSTROUTLEN];

	form.style = FLOATDECIMAL;
	form.digits = precision;
	num2dec(&form, d, &result);
	
	// Use fixed-point notation if it fits within a small enough space
	if (3 >= result.exp && result.exp >= -precision - 3)
	{
		form.style = FIXEDDECIMAL;
		form.digits = -result.exp;
		num2dec(&form, d, &result);
	}

	dec2str(&form, &result, output);

	return *this << output;
}

Again, this code should not be called at interrupt time, due to the use of NumToString. However, it would be very easy to replace the call to NumToString with something homegrown that doesn't move memory.

Note that it would not be hard to make PascalStringStream fully compatible with Mac OS international number formatting, which would not be possible with a standard ostream.

Putting it all to use

The reset method is provided as a convenience. It enables a single stream to be reused multiple times in the same function, and because it returns a reference to the stream, it can be used as the first operation in a cascade:

	gMessage.reset() << "\pReading data from " << filename;

An entire cascade expression can also be passed as the argument to a function:

	SetDialogItemText(item, message << "Hello, " << name);

In this case, a C string literal has been used instead of a Pascal one; it now makes very little difference which kind is used.

Rather than defining a single stream at the start and reusing it repeatedly, it is also possible to use unnamed temporaries for creating and passing stream-generated text:

	SetDialogItemText(item,
		PascalStringStream() << "Hello, " << name);

This allocates and constructs an unnamed temporary variable on the stack, performs all the operations in the cascade, passes a const unsigned char * to SetDialogItemText, and destroys the variable when it is no longer needed. Quite a lot of work in one line! And not too cryptic either.

The only drawback is that the compiler's idea of 'no longer needed' may be the end of the current block, and not just the statement containing the call to SetDialogItemText. If you use many calls like this in one function, you can end up needing a lot of stack space. This isn't usually much of a problem, but you do need to be aware of it. The best solution is to have a reusable named variable instead. Another is to limit the scope using additional sets of braces. It is a pity that one of the final additions to the official C++ standard was to increase the longevity of unnamed temporaries.

A note on localization

All of our examples have used embedded string literals and string variables. In a production program, we would need to allow for localization by storing strings in resources. It is quite possible to do this in combination with PascalStringStream, and a class that can assist with this is mentioned in a later section.

However, there is a well-known localization issue that PascalStringStream does not help to address. This concerns the order of substitutions in a generated message. Different natural languages may need to make the data insertions in different orders, so the localization process needs to be able to specify the relative order of the different parts of the message. This is handled in a primitive way by the ParamText mechanism, but a general solution is more of a challenge.

A solution is more or less impossible when using PascalStringStream, because the substitution pattern is hard-coded within the program. On the other hand, allowing substitutions to be specified apart from the code makes it impossible to check for consistency with the data, which was one of our key design criteria. Real life is full of conflicts!

PascalStringStream is therefore not a universal solution to all text-handling needs within the UI. It is however both powerful and easy to use in a wide variety of situations. It is especially valuable for debugging, and for the development of applications that will not be heavily localized.

Bombs Away!

Before I developed PascalStringStream, I thought I was very smart in defining an error-reporting function that used ParamText to concatenate its arguments, and used C++ overloading to allow this to be called with a variety of argument numbers and types. This worked quite well in some ways, although I sometimes found it frustrating not being able to handle more than four substitutions.

I definitely found it a problem, however, that my library function was dependent on resources. This meant that the appropriate resource file had to be included in the build alongside the library code, and resource IDs for the ALRT and DITL had to be reserved for the library. It also meant that my reporting functions were not completely bombproof. If the resource map got scribbled on and was no longer functional, or the resources didn't get included in the build, there was nothing I could do except 'beep in despair'.

Another frustration was that the Alert always had a fixed size, regardless of the amount of text in it. It needed to be big enough to hold the largest amount of text that the function was capable of displaying (4 x 255 bytes), and yet this looked clumsy in the common case when only a few bytes were used.

I must confess I was rather envious of our fellow-programmers 'on the other side'. That system has an API that takes a string and puts up a dialog box that is sized to fit the text. There is virtually no way that the call can fail since it is handled by the system.

That was until I thought of using the Mac OS Notification Manager. This system-provided facility does not depend on resources, is almost incapable of failing, can be used from an interrupt routine or extension, and (on Mac OS 8) sizes itself to fit the text! The only restriction is that it doesn't support the ParamText mechanism. That is what finally spurred me into designing PascalStringStream.

A better mousetrap

I replaced my once-great set of error functions with very economical equivalents layered on top of PascalStringStream and the Notification Manager. To assist with this, I wrote a simple function that wrapped the NM interface, called Notify:

static pascal void callbackProc(NMRecPtr record) {
	record->nmRefCon = 1;	// Signal completion
}

void Notify(const unsigned char* msg, bool beep) {

	// Code Fragment Manager stuff
#if TARGET_RT_MAC_CFM
	RoutineDescriptor callbackRoutine =
			BUILD_ROUTINE_DESCRIPTOR(uppNMProcInfo,
					 callbackProc);
#else
	#define callbackRoutine callbackProc
#endif

	if (msg == 0)
		msg = "\p<null message>";

	// Prepare notification request
	NMRec request;
	request.qType = nmType;
	request.nmMark = 1;
	request.nmIcon = 0;
	request.nmSound = beep ? Handle(-1) : 0; // -1 means system beep
	request.nmStr = const_cast<StringPtr>(msg);
	request.nmResp = &callbackRoutine;
	request.nmRefCon = 0;
	
	// This can only fail if qType != nmType, which is impossible here
	if (NMInstall(&request) != noErr) {
		SysBeep(60);
		return;
	}
	
	// Await completion before destroying msg
	while (request.nmRefCon == 0) {
		EventRecord event;
		// Wait 10 ticks, and don't fetch any events
		WaitNextEvent(0, &event, 10, 0);
	}

	NMRemove(&request);
}

Of course, the call to WaitNextEvent would need to be changed if this code was used in an extension or an interrupt routine. The details of the replacement would be determined by the context. The most likely strategy would be to require that msg was global or static, and to enable auto-removal of the NMRec by the Notification Manager instead of the callback routine. A more sophisticated solution would be to make Notify a mix-in class instead of a function, with a virtual method for the callback.

Wrapping it up

The error-reporting functions now look like this:

// Use a global to avoid double-evaluation in macros
static OSErr					gLastError;
// Save space by defining repeated text once
static unsigned char	gErrorIntro[] = "\p\r\rError ";

// Display a stream message, with and without a beep
#define Message(X)	Notify(PascalStringStream() << X, false)
#define Error(X)		Notify(PascalStringStream() << X, true)

// Display a stream message and an error number
#define Failure(E, X)	Error(X << gErrorIntro << (E))

// Conditionally display an OS error message
#define OSFailure(E, X) \
	((gLastError = (E)) != noErr && \
	 (Failure(gLastError, X), true))

// Conditionally display a Resource error message
#define ResFailure(H, X) \
	((H) == nil && \
	 (gLastError = ResError(), Failure(gLastError, X), true))

These functions are used like this:

Message("\pHello, " << name);

Failure(theErr, "\pCould not write " << filename);

if (OSFailure(FSpOpenDF(&spec, fsWrPerm, &refNum),
			"Could not open "<<name<<" for writing")
	return;

The reason these are defined as macros and not functions is twofold. First, a macro can supply the repetitive PascalStringStream() << part. There is no way to avoid including this somewhere in the caller. Second, with the conditional versions, the message-building code does not need to be evaluated when there is not an error. If these were real functions, the message would have to be passed as an argument and therefore would always be evaluated.

Bells And Whistles

Although we chose not to include field-width and justification features in our stream class, a few more features would be extremely useful when displaying debug messages, with DebugStr or with Notify. In particular, we do not have any way to display hexadecimal values. It is also very helpful to have a convenient way of displaying four-character codes such as file and resource types.

It would be possible to add more machinery to PascalStringStream to handle these cases, but there is a cleaner way to achieve the same result. Recall how our number-formatting routines created a text representation of the number in a buffer on the stack, and then appended that to the main string. We can use exactly the same technique for other types of data, without adding more methods to our stream. Instead, we create a subclass of PascalString for each type that we wish to format. This will have a constructor that converts the datatype into its text representation. The newly constructed object can then be passed to the stream for inclusion in the output. An unnamed temporary is ideal for this purpose.

Applying this to the additional features already mentioned, we can define classes hex and ostype that are used like this:

	message << "Mask: " << hex(mask, 8);
	message << "File type: " << ostype(type);

The first line will zero-fill the value of mask to 8 digits and append it to message. The second line appends the four characters of type, without quotes.

These classes are declared in a header file like this:

class hex : public PascalString<sizeof(unsigned long) * 2> {
	public:
		hex(unsigned long x, int width = 0);
};

class ostype : public PascalString<sizeof(OSType)> {
	public:
		ostype(OSType t);
};

The default value of the width parameter of the hex constructor suppresses zero-filling. An additional constructor taking a void * argument could be defined if it is necessary to display the values of pointers.

The implementation of these constructors can be placed in a .cp file, since these are not template classes. The hex constructor chops its argument into nibbles and appends the corresponding characters to the buffer. The ostype constructor performs a four-byte copy from its argument to its buffer and sets the length to four. In both cases, the underlying string buffer is just big enough to contain the corresponding data, and no more. As you can see, any constant expressions can be used as the size.

A similar class could be defined that initializes itself with a string stored in a resource. Such helper classes are easy to implement and easy to use, largely because of the design of the PascalString class that they are based on.

The Thoroughly Modern Macintosh

There is no longer a need to use printf in a modern C++ program. The iostream classes are superior in almost every way. In some situations standard iostreams come at too high a cost, or don't work with our data, but we still don't have to sacrifice the entire ostream paradigm. The amazing flexibility of C++ allows us to develop extensions to the language that are compatible with the standard library, and yet are well adapted to our specific context.

The solution involves templates, inheritance, inline and non-inline functions, and the use of unnamed temporaries, yet nothing is obscure or complicated. An average programmer with suitable experience should be able to produce this kind of tool on a regular basis. The effort involved in developing the PascalString and PascalStringStream classes was not high, but the results have wide-ranging potential for reusability.

So throw out those out-of-date techniques, and spend a little time each week polishing your tools-the results are definitely worth it.


Neil Mayhew works for Wycliffe Bible Translators, a non-profit organization dedicated to translating the Bible for the world's 400 million people that do not have it in their own language. Neil started programming in C in 1983, and graduated to the Mac in 1989. When he's not at his Mac or trying to beat his kids at video games you might find him flying a stunt kite if it's windy, or throwing a boomerang if it's not.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

The beginner's guide to Warbits
Warbits is a turn-based strategy that's clearly inspired by Nintendo's Advance Wars series. Since turn-based strategy games can be kind of tricky to dive into, see below for a few tips to help you in the beginning. Positioning is crucial [Read... | Read more »
How to upgrade your character in Spellsp...
So you’ve mastered the basics of Spellspire. By which I mean you’ve realised it’s all about spelling things in a spire. What next? Well you’re going to need to figure out how to toughen up your character. It’s all well and good being able to spell... | Read more »
5 slither.io mash-ups we'd love to...
If there's one thing that slither.io has proved, it's that the addictive gameplay of Agar.io can be transplanted onto basically anything and it will still be good fun. It wouldn't be surprising if we saw other developers jumping on the bandwagon,... | Read more »
How to navigate the terrain in Sky Charm...
Sky Charms is a whimsical match-'em up adventure that uses creative level design to really ramp up the difficulty. [Read more] | Read more »
Victorious Knight (Games)
Victorious Knight 1.3 Device: iOS Universal Category: Games Price: $1.99, Version: 1.3 (iTunes) Description: New challenges awaits you! Experience fresh RPG experience with a unique combat mechanic, packed with high quality 3D... | Read more »
Agent Gumball - Roguelike Spy Game (Gam...
Agent Gumball - Roguelike Spy Game 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Someone’s been spying on Gumball. What the what?! Two can play at that game! GO UNDERCOVERSneak past enemy... | Read more »
Runaway Toad (Games)
Runaway Toad 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: It ain’t easy bein’ green! Tap, hold, and swipe to help Toad hop to safety in this gorgeous new action game from the creators of... | Read more »
PsyCard (Games)
PsyCard 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: From the makers och Card City Nights, Progress To 100 and Ittle Dew PSYCARD is a minesweeper-like game set in a cozy cyberpunk... | Read more »
Sago Mini Robot Party (Education)
Sago Mini Robot Party 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: -- Children's Technology Review Editor's Choice -- | Read more »
Egz – The Origin of the Universe (Games...
Egz – The Origin of the Universe 1.0.2 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.2 (iTunes) Description: ►►► Special offer until 2nd may : get the game at 2.99€ instead of 3.99€ ! ◄◄◄ Egz is a mesmerizing mix... | Read more »

Price Scanner via MacPrices.net

Mac minis on sale for up to $100 off MSRP
B&H Photo has Mac minis on sale for up to $100 off MSRP including free shipping plus NY sales tax only: - 1.4GHz Mac mini: $449 $50 off MSRP - 2.6GHz Mac mini: $649 $50 off MSRP - 2.8GHz Mac mini... Read more
13-inch Retina MacBook Pros on sale for up to...
B&H Photo has 13″ Retina MacBook Pros on sale for $130-$200 off MSRP. Shipping is free, and B&H charges NY tax only: - 13″ 2.7GHz/128GB Retina MacBook Pro: $1169 $130 off MSRP - 13″ 2.7GHz/... Read more
Apple price trackers, updated continuously
Scan our Apple Price Trackers for the latest information on sales, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. We update the trackers continuously: - 15″... Read more
SanDisk Half-Terabyte SSD Optimized for Every...
SanDisk Corporation has announced the SanDisk Z410 SSD, a cost-competitive, half-terabyte solid state drive (SSD) that enables manufacturers to design for a broad range of desktop PCs and laptops.... Read more
Churchill Downs Racetrack Selects VenueNext t...
Churchill Downs Racetrack has announced an agreement with VenueNext to implement its technology platform for the start of Churchill Downs 2016 Spring Meet, which includes the 142nd running of the... Read more
Record 700 Million Pounds of CE Recycled in 2...
The Consumer Technology Association (CTA) reports that a record-setting 700 million pounds of consumer electronics (CE) have been recycled under the eCycling Leadership Initiative (ELI). According to... Read more
Price drops on clearance 12-inch Retina MacBo...
B&H Photo has dropped prices on leftover 2015 12″ Retina MacBooks with models now available starting at $999. Shipping is free, and B&H charges NY tax only: - 12″ 1.1GHz Gray Retina MacBook... Read more
15-inch Retina MacBook Pros available for $20...
B&H Photo has 15″ Retina MacBook Pros on sale for up to $210 off MSRP. Shipping is free, and B&H charges NY tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799 $200 off MSRP - 15″ 2.5GHz Retina... Read more
Target offers Apple Watch Sport for $50 off M...
Target has Apple Watch Sports on sale for $50 off MSRP for a limited time. Choose free shipping or free local store pickup (if available). Sale prices for online orders only, in-store prices may vary... Read more
Apple restocks Certified Refurbished Mac mini...
Apple has restocked Certified Refurbished 2014 Mac minis, with models available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz Mac mini: $419 $... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Restaurant Manager (Neighborhood Captain) - A...
…in every aspect of daily operation. WHY YOU'LL LIKE IT: You'll be the Big Apple . You'll solve problems. You'll get to show your ability to handle the stress and Read more
Restaurant Manager (Neighborhood Captain) - A...
…in every aspect of daily operation. WHY YOU'LL LIKE IT: You'll be the Big Apple . You'll solve problems. You'll get to show your ability to handle the stress and Read more
Simply Mac *Apple* Specialist- Service Repa...
Simply Mac is the largest premier retailer of Apple products in the nation. In order to support our growing customer base, we are currently looking for a driven Read more
*Apple* Retail - Multiple Positions - Apple,...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.