STANDARD I/O FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~ There are twenty-one functions in earth.library which deal with I/O. (thirty-two if you program in 'C'). Six of these are printf() type functions (twelve if you program in 'C'), five are scanf() type functions (ten if you program in 'C'), and the remainder are miscellaneous things like puts() and gets(). To avoid name conflicts, stdio functions within earth.library are spelt in mixed case, and have names which begin with underscore (for instance, our version of printf() is called _PrintF()). It's worth looking at the docs for _PrintF() and _ScanF(), as these functions not only obey completely the ANSI standard (with one exception), they surpass it, with a wealth of additional features. For instance, in _PrintF(), you can replace the width and/or the precision fields with an asterisk, which will cause the width and/or precision to be read from the argument stream. I borrowed this trick from Turbo-C (which is only available for inferior PC machines), but whereas Turbo-C will only allow you to specify the width in this way, earth.library allows you to specify the precision as well. So now we're one up on PC users. Another trick I borrowed from Turbo-C is the "%[]" escape-sequence in _ScanF(). This allows you to input a string consisting of characters from a specified set, or else characters NOT contained in a specified set. This allows you to input strings containing spaces (for instance), or to allow a choice of separator in the input stream. Again, however, I decided to take things one stage further. The escape-sequence "%+s" (note the plus sign) is an EarthSoft invention, which allows you to input a possibly quoted string. Quoted strings may, of course, contain whitespace of any type, and you can include the delimiter itself within the string by supplying it twice. There are some blind spots in the ANSI standard for printf(), and by and large, each version of printf() has its own interpretation of what to do in these circumstances. One such ambiguity is what meaning we can attribute to the precision field when printing an integer. K&R does not specify this at all. Turbo-C takes it to mean the number of significant digits to print accurately, and MicroSoft C takes it to mean the minimum number of digits to print (and hence will pad with leading zeroes if necessary). I have decided that BOTH of these interpretations are pretty stupid. Turbo-C's idea is daft because since the number is an integer it is perfectly possible to print ALL digits accurately, and MicroSoft C's idea is redundant, since you can do that using the width field only (by using a leading zero on the width). Therefore EarthSoft's _PrintF() uses neither of these approaches, and the precision field is IGNORED for integers. Another possible ambiguity arises in _ScanF(). What do you do if a non-whitespace in the format string fails to match the next character in the input stream? Again, K&R has nothing to say on the subject, other than "Ordinary characters ... are expected to match the next non-whitespace in the input stream". Pretty helpful, no? Turbo-C says that if they don't match then the character from the input stream is treated as the first character of the next thing to be input (in other words, characters in the format string are skipped up to the next '%'). MicroSoft C says, simply, if they don't match then abort. I have followed the MicroSoft-C approach - it is far less confusing. Finally, I would like to mention the one and only case when _PrintF() fails to comply with ANSI. It is this: if you print a hexadecimal number using "%x" then any alphabetic characters will be printed in UPPER case. The reason I have done this is to remain compatable with ARP's Printf(), and others. Ultimately, the blame lies with the RawDoFmt() function in "exec.library", which erroneously interpretted "%x" as "%X". Now, alas, compatability rules, and I have no choice but to follow suit. To get round the problem, I have devised a new escape sequence, "%/x", which will print a hex number in lower case - should you ever need to do so. The _PrintF() and _ScanF() family of functions are extremely powerful, and may be used for purposes other than straightforward input and output. For example, suppose you want to parse a CLI command line for an application which allows floating point numbers to be supplied on the command line. There is no template type which means floating point number, and the "/N" template type (WB2.0+ only) will only understand integers. The only solution is to accept the argument as a string, and then convert it from ASCII string to float or double. You might at first suppose that you'd need an atof() (ASCII to Float) type function to do the conversion, but of course this is not true. _SScanF() can do the job just as well. From printing "hello world" to printing integers in decimal, octal, or hexadecimal, to printing floating point numbers in either standard or floating point form. Virtually any kind of conversion is possible with _PrintF() and family. And, of course, _ScanF() and family will do the reverse conversions. Also, look out for "Amiga specials", like HookPrintF() and HookScanF(). They might come in handy one day. The functions pertaining to this document are as follows. Note that the 'V' functions are only of benefit to C programmers. _PrintF() _VPrintF() _ScanF() _VScanF() _SPrintF() _VSPrintF() _SScanF() _VSScanF() _SNPrintF() _VSNPrintF() _FPrintF() _VFPrintF() _FScanF() _VFScanF() HookPrintF() VHookPrintF() HookScanF() VHookScanF() RawPrintF() RawScanF() PutChar() GetChar() FPutC() FGetC() PutS() GetS() FPutS() FGetS() GetSN() FGetSN()