This article will cover the theory over formatted printing (i.e. printf()).
How printf() Works?
Your first step towards a reliable printf() function is the understanding of its work. Had you ever tried to imitate va_list and friends via a void** taking the example of a specific language, ... General principles and goals - Localising - Translation tools - Babel Manual:Language - or similitar technics? It surely won't work! You must use the va_list provided in the freestanding version of <stdarg.h> (or and equivalent implementation) in order to be able to use variadic functions. Assuming the use of <stdarg.h>, this is the prototype for printf()
int printf(const char *format, ...);
Have you seen the other members of the printf() family? They're
- printf(): Write formatted data to stdout
- fprintf(): Write formatted data to stream
- sprintf(): Write formatted data to buffer
- snprintf(): Write formatted data to buffer, limits maximum characters written
- vprintf(): Write formatted data to stdout, uses a va_list instead of ...
- vfprintf(): Write formatted data to stream, uses a va_list instead of ...
- vsprintf(): Write formatted data to buffer, uses a va_list instead of ...
- vsnprintf(): Write formatted data to buffer, limits maximum characters written, uses a va_list instead of ...
And the abstractions...
- printf(): Wraps over vprintf()
- fprintf(): Wraps over vfprintf()
- sprintf(): Wraps over vsprintf()
- snprintf(): Wraps over vsnprintf()
- vprintf(): Wraps over vfprintf()
- vfprintf(): Does the work!
- vsprintf(): Wraps over vsnprintf() (with a magical number as limit).
- vsnprintf(): Wraps over vfprintf() with fmemopen()
But, hey! This is a user-space C library example! Yes, it is. You'll more than likely only provide a printf() that does what vfprintf() is intented to do, but in one shot. Basically, the worker function will print where it must print, until finding a % character. If it's followed by another %, it's printed and process contiues. If it's followed by a valid specifier character, its parsing begins. Else the character is printed and process continues. We'll explain in detail the implementation of each item later.
Let's define some constants that we'll use a lot later on
#define FLAG_LEFT 0x01 // The '-' flag #define FLAG_SIGN 0x02 // The '+' flag #define FLAG_SPACE 0x04 // The ' ' flag #define FLAG_TYPE 0x08 // The '#' flag #define FLAG_ZERO 0x10 // The '0' flag
The General Recolection
Once you have found something after a %, you should start by declaring three signed variables: