/*
 *			p r i n t f . c
 *
 * Formatted output to the "standard" device.
 */

/*)LIBRARY
*/

#ifdef	DOCUMENTATION

title	printf	Formatted Output Conversion
index		Formatted output conversion

synopsis
	.s.nf
	printf(format, arg1, ...)	
	char		*format;

	fprintf(stream, format, arg1, ...)
	FILE		*stream;
	char		*format;

	char *
	sprintf(buffer, format, arg1, ...);
	char		*buffer;
	char		*format;

	c_doprnt(format, argvec, iov)
	char		*format;
	int		*argvec[];
	FILE		*stream;
	.s.f
 Description

	printf() converts, formats, and prints its arguments, under control
	of the first argument, writing output to stdout. fprintf()
	writes its output to the indicated file.  sprintf() writes its
	output to the indicated string buffer.  c_doprnt() is the internal
	print formatter which is called by printf, etc.  

	sprintf() returns a pointer to the EOS at the end of the output
	buffer.  This is not necessarily transportable.

	The format argument is a character string which contains two
	types of objects: plain characters, which are simply copied
	to the output stream, and conversion specifications, each of
	which causes conversion and printing of the next successive
	argument to printf.

	Each conversion specification is introduced by the character %.
	Following the %, there may be
	.lm +4
	.s.i -4;-###an  optional  minus  sign  "-"  which  specifies left
	adjustment of the converted argument in the indicated
	field.
	.s.i -4;-###an optional digit string specifying field  width.  If
	the  converted argument has fewer characters than the
	field width, it will be blank-padded on the left  (or
	right, if  the  left-adjustment  indicator  has  been
	given) to make up the  field  width.   If  the  field
	width  is  specified as '*' or '?', the next argument
	is used.  (Note: '?' is  obsolete.)  If the  width is
	specified  with a leading  zero,  zeros are  used for
	padding instead of blanks.  This zero  does NOT imply
	an octal field width.  For example, assume the  value
	123 is to be printed:
	
		%d	"123"
		%5d	"  123"
		%-5d	"123  "
		%05d	"00123"
	.s.i -4;-###an  optional  period "." which serves to separate the
	field width from the precision argument.
	.s.i -4;-###an optional digit string (precision) which  specifies
	the number of digits  to be printed from a string.   If the
	precision is  specified  as  '*'  or  '?',  the  next
	argument is used.  If the precision is zero, no bytes in the
	string will be printed.
	.s.i -4;-###a character which indicates the  type  of  conversion
	   to be applied.
	.lm -4
	The conversion characters and their meanings are
	.lm +4.s
	.i -4;b###Binary (bits)
	.i -4;d###Signed-decimal
	.i -4;u###Unsigned-decimal
	.i -4;o###Octal
	.i -4;x###Hexadecimal, 10-15 are represented by a-f
	.lm -4.s
	The  integer  argument  is converted to decimal,
	octal, or hexadecimal   notation   respectively.
	Any   of   the   conversion  characters  may  be
	capitalized or preceeded  by  'l'  to  signal  "long"   integer
	argument.
	.lm +4
	.s.i -4;c###The argument character is printed.  If the argument
	is zero (EOS), it will be ignored.
	.s.i -4;q###The (16-bit) integer is printed as a pair of
	octal bytes in the format "123.456"  The bytes follow
	the PDP-11 order (high order byte first).  This format
	is not transportable to other systems.
	.s.i -4;r###Remote format.  The next  printf()  argument  is
	the format.  Note that this is not a subroutine.
	The current format is not processed further. For
	example:

	    bug(args)
	    {
		error("Error at %r", &args);
	    }

	This routine might be called as follows:

	    bug("Error %d at %s\n", val, name);

	%r is not transportable to  all  implementations
	of  the  standard  library.  It does not word on
	Vax-11 C, for example.  c_doprnt() may  be  used
	as shown below for similar functionality.
	.s.i -4;s###The  argument is taken to be a string (character
	pointer) and  characters  from  the  string  are
	printed  until  a  null  character  or until the
	number of characters indicated by the  precision
	specification  is   reached;   however   if  the
	precision   specification  is  0  or missing all
	characters up to null are printed.
	.s.lm -4
	If no recognizable character appears after the %, that character
	is printed; thus % may be printed by the use of the string %%.
	In no case does a non-existant or small field width cause truncation
	of a field; padding takes place only if the specified field
	width exceeds the actual width.  Characters generated by printf()
	are printed by calling putchar().

	c_doprnt() is the internal print formatter called by all
	"top-level" print functions.  It is functionally identical
	to the Unix and Vax-11 C _doprnt() library routine.  Unfortunately,
	the leading '_' conflicts with RSX-11M file services library
	routine conventions, requiring the use of an unique prefix.
	If your programs wish to call c_doprnt,
	a potentially transportable procedure would be:

	    #ifdef decus
		c_doprnt(format, args, iov);
	    #else
		_doprnt(format, args, iov);
	    #endif

	You should assume, however, that _doprnt() is not necessarily
	present on all implementations of the "standard library."

Bugs

#endif

#include	<stdio.h>
#define	EOS	'\0'			/* native stdio.h doesn't define EOS */
  
printf(fmt, args)
{
	c_doprnt(fmt, &args, stdout);
}

#ifdef	TESTING
/*)BUILD
	$(FILES)	= { printf doprnt }
*/

char	buffer[80];
char	format[80];

main() {
	printf("just text\n");
	printf("one number (one-two-three) %d\n", 123);
	printf("string \"%s\"\n", "Hello there");
	printf("char '%c'\n", 'x');
	for (;;) {
		clearerror(stdin);
		fputs("format: ", stdout);
		fflush(stdout);
		if (gets(format) == NULL)
			break;
		for (;;) {
			printf("Arg for \"%s\", <CR> to exit: ", format);
			fflush(stdout);
			if (gets(buffer) == NULL || buffer[0] == EOS)
				break;
			printf("buffer = \"%s\" (%d): ", buffer, atoi(buffer));
			printf(format, atoi(buffer));
			printf("\n[");
			printf(format, atoi(buffer));
			printf("]\n");
		}
	}
}

#endif
