%c and %s are the two simplest specifiers: no numeric conversion, no
sign handling, no base arithmetic. They are the right place to start
because getting them right confirms that the variadic mechanism, the output
helpers, and the return-value accounting all work before the integer
conversions are added.
%c
%c prints a single character. The character is passed to printf as an
int — the same promotion convention used by tci_isascii and the rest of
libtci's character functions. Inside dispatch, va_arg(*args, int)
reads the promoted value; the cast to unsigned char extracts the low
byte before writing:
if (spec == 'c')
return (tci_putchar_fd((unsigned char)va_arg(*args, int), 1));The (unsigned char) cast is required for the same reason it appears in
tci_isalpha: plain char may be signed, and values above 127 would
be negative before the write if the cast were omitted. One byte is
written; the function returns 1.
%s
%s prints a null-terminated string. tci_putstr_fd already handles this,
including the NULL case:
if (spec == 's')
return (tci_putstr_fd(va_arg(*args, char *), 1));The NULL pointer behaviour — printing (null) — is what libc printf
does on Linux. The tester expects this.
Run man 3 printf — search for "s conversion". The manual specifies that
if the precision is given and is less than the string length, only that
many bytes are written. Precision handling is covered on the flags page;
for now, the full string is always written.
Build and test
Build and run the tester:
make re
bash test.shThe remaining specifiers are stubs that return 0 — their rows will
fail. That is expected at this stage. Confirm that the %c and %s
rows pass before moving on. The integer specifiers are next.