diff options
Diffstat (limited to 'src/stdio/printf.c')
-rw-r--r-- | src/stdio/printf.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/stdio/printf.c b/src/stdio/printf.c new file mode 100644 index 00000000..57684158 --- /dev/null +++ b/src/stdio/printf.c @@ -0,0 +1,111 @@ +#include <stdio.h> +#include "stdarg.h" +#include "nonstd/internal.h" +#include "nonstd/io.h" + +/** write formatted output **/ +int printf(const char *format, ...) +{ + + int ret = 0; + va_list ap; + struct io_options opt = {0}; + opt.fnname = "printf"; + opt.stream = stdout; + va_start(ap, format); + ret = __printf(&opt, format, ap); + va_end(ap); + + /* + RETURN_SUCCESS(the number of characters written); + RETURN_FAILURE(NEGATIVE); + */ + return ret; +} + +/*** +writes a formatted string to IDENTIFIER(stdout). + +The argument ARGUMENT(format) controls the output. It points to a +NUL-terminated multibyte character string. Characters other than CHAR(%) +are output unmodified. The CHAR(%) begins a conversion specifier, which is +made up of the following: + +__(Zero or more CONCEPT(flags, flags)) +__(An optional CONCEPT(fieldwidth, field width) <!-- TODO: describe -->) +__(An optional CONCEPT(precision, precision) <!-- TODO: describe -->) +__(An optional CONCEPT(typewidth, type width) <!-- TODO: describe -->) +__(The CONCEPT(typespec, type specifier) <!-- TODO: describe -->) + +CONCEPT_DEFINITION(flags, Flags) +The following flags modify output as indicated: + +FLAG(CHAR(-), Left-justify this field (the default is right-justification)) +FLAG(CHAR(+), Always include a plus or minus sign for signed values (the default is only to display a sign for negative values)) +FLAG(SPACE, TODO: I am not entirely clear on this myself) +FLAG(CHAR(#), TODO: Or this one) +FLAG(CHAR(0), Include leading zeros unless TODO) + +CONCEPT_DEFINITION(fieldwidth, Field Width) +If the provided value has fewer characters than specified here, it will be +padded with spaces or zeroes to fill the desired width. The width is specified +as a decimal integer or a CHAR(*). If CHAR(*) is specified, the width will +be taken from the next argument as an TYPE(int). + +CONCEPT_DEFINITION(precision, Precision) +The maximum number of digits in CHAR(d), CHAR(i), CHAR(o), CHAR(u), +CHAR(x), and CHAR(X) conversions; or, the number of digits after the +decimal for CHAR(e), CHAR(E), and CHAR(f) converions; or, the maximum +number of significant digits for CHAR(g) and CHAR(G) conversions; or, the +maximum number of characters from a string in CHAR(s) conversions. The +precision is specified by a CHAR(.) followed by a decimal integer, a +CHAR(*), or nothing. If CHAR(*) is specified, the precision will be taken +from the next argument as an TYPE(int). If nothing is specified, it is +the same as specifying CHAR(0). + +CONCEPT_DEFINITION(typewidth, Type Width) +The following type widths can be applied to ensure accurate type conversions +following normal argument type promotions: +FLAG(CHAR(h), `Converts the next argument to TYPE(short int) or + TYPE(unsigned short int) for CHAR(d), CHAR(i), CHAR(o), + CHAR(u), CHAR(x), and CHAR(X) conversions.') +FLAG(CHAR(h), `Specifies that pointer at an CHAR(n) conversion is a + TYPE(short int).') +FLAG(CHAR(l), `Converts the next argument to TYPE(long int) or + TYPE(unsigned long int) for CHAR(d), CHAR(i), CHAR(o), + CHAR(u), CHAR(x), and CHAR(X) conversions.') +FLAG(CHAR(l), `Specifies that pointer at an CHAR(n) conversion is a + TYPE(long int).') +FLAG(CHAR(L), `Converts the next argument to TYPE(long double) for + CHAR(e), CHAR(E), CHAR(f), CHAR(g), and CHAR(G) conversions.') + +CONCEPT_DEFINITION(typespec, Type Specifier) +The final character of the conversion specifier indicates the type of value +to be output: + +FLAG(CHAR(d), `Converts an TYPE(int) to a signed decimal number.') +FLAG(CHAR(i), `Same as CHAR(d).') +FLAG(CHAR(o), `Converts an TYPE(unsigned int) to octal notation.') +FLAG(CHAR(u), `Converts an TYPE(unsigned int) to decimal notation.') +FLAG(CHAR(x), `Converts an TYPE(unsigned int) to hexadecimal notation using lowercase letters.') +FLAG(CHAR(X), `Converts an TYPE(unsigned int) to hexadecimal notation using uppercase letters.') +FLAG(CHAR(f), `Converts a TYPE(double) to decimal notation.') +FLAG(CHAR(e), `Converts a TYPE(double) to scientific notation with a lowercase CHAR(e).') +FLAG(CHAR(E), `Converts a TYPE(double) to scientific notation with an uppercase CHAR(E).') +FLAG(CHAR(g), `FIXME: Same as CHAR(f) or CHAR(e) depending on precision.') +FLAG(CHAR(G), `FIXME: Same as CHAR(f) or CHAR(E) depending on precision.') +FLAG(CHAR(c), `Converts a TYPE(unsigned char) to a character.') +FLAG(CHAR(s), `Converts a pointer to an array of TYPE(char) to a NUL-terminated string.') +FLAG(CHAR(p), `Converts a TYPE(void *) to an implementation-defined format.') +FLAG(CHAR(n), `Causes the function to write the total number of characters output so far to an TYPE(int) pointed at by the next argument.') +FLAG(CHAR(%), `Outputs a literal CHAR(%).') +***/ + +/* +IMPLEMENTATION(`The format of CHAR(p) conversions', `STRING(0x%0ARGUMENT(n)x), where ARGUMENT(n) is the number of hexadecimal digits in a canonical address on the platform of execution.') +UNDEFINED(`Precision with a conversion specifier other than CHAR(d), CHAR(i), CHAR(o), CHAR(u), CHAR(x), CHAR(X), CHAR(e), CHAR(E), CHAR(f), CHAR(g), CHAR(G), or CHAR(s)') +UNDEFINED(TODO: Using h or l for !(diouxXn) or L for !(eEfgG)) +*/ +/* +STDC(1) +*/ |