diff options
| author | svn2git <svn2git@FreeBSD.org> | 1993-11-01 08:00:00 +0000 |
|---|---|---|
| committer | svn2git <svn2git@FreeBSD.org> | 1993-11-01 08:00:00 +0000 |
| commit | 8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (patch) | |
| tree | c5b2ce776438e0a52b492a2ab6ab41360b8ba1f6 /usr.bin/printf | |
Diffstat (limited to 'usr.bin/printf')
| -rw-r--r-- | usr.bin/printf/Makefile | 5 | ||||
| -rw-r--r-- | usr.bin/printf/printf.1 | 272 | ||||
| -rw-r--r-- | usr.bin/printf/printf.c | 307 |
3 files changed, 584 insertions, 0 deletions
diff --git a/usr.bin/printf/Makefile b/usr.bin/printf/Makefile new file mode 100644 index 000000000000..bb7f410281c7 --- /dev/null +++ b/usr.bin/printf/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 5.3 (Berkeley) 5/11/90 + +PROG= printf + +.include <bsd.prog.mk> diff --git a/usr.bin/printf/printf.1 b/usr.bin/printf/printf.1 new file mode 100644 index 000000000000..34f0668f52c5 --- /dev/null +++ b/usr.bin/printf/printf.1 @@ -0,0 +1,272 @@ +.\" Copyright (c) 1989, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)printf.1 5.11 (Berkeley) 7/24/91 +.\" +.Dd July 24, 1991 +.Dt PRINTF 1 +.Os +.Sh NAME +.Nm printf +.Nd formatted output +.Sh SYNOPSIS +.Nm printf format +.Op arguments ... +.Sh DESCRIPTION +.Nm Printf +formats and prints its arguments, after the first, under control +of the +.Ar format . +The +.Ar format +is a character string which contains three types of objects: plain characters, +which are simply copied to standard output, character escape sequences which +are converted and copied to the standard output, and format specifications, +each of which causes printing of the next successive +.Ar argument . +.Pp +The +.Ar arguments +after the first are treated as strings if the corresponding format is +either +.Cm c +or +.Cm s ; +otherwise it is evaluated as a C constant, with the following extensions: +.Pp +.Bl -bullet -offset indent -compact +.It +A leading plus or minus sign is allowed. +.It +If the leading character is a single or double quote, or not a digit, +plus, or minus sign, the value is the ASCII code of the next character. +.El +.Pp +The format string is reused as often as necessary to satisfy the +.Ar arguments . +Any extra format specifications are evaluated with zero or the null +string. +.Pp +Character escape sequences are in backslash notation as defined in the +draft proposed +.Tn ANSI C +Standard +.Tn X3J11 . +The characters and their meanings +are as follows: +.Bl -tag -width Ds -offset indent +.It Cm \ea +Write a <bell> character. +.It Cm \eb +Write a <backspace> character. +.It Cm \ef +Write a <form-feed> character. +.It Cm \en +Write a <new-line> character. +.It Cm \er +Write a <carriage return> character. +.It Cm \et +Write a <tab> character. +.It Cm \ev +Write a <vertical tab> character. +.It Cm \e\' +Write a <single quote> character. +.It Cm \e\e +Write a backslash character. +.It Cm \e Ns Ar num +Write an 8-bit character whose +.Tn ASCII +value is the 1-, 2-, or 3-digit +octal number +.Ar num . +.El +.Pp +Each format specification is introduced by the percent character +(``%''). +The remainder of the format specification includes, +in the following order: +.Bl -tag -width Ds +.It "Zero or more of the following flags:" +.Bl -tag -width Ds +.It Cm # +A `#' character +specifying that the value should be printed in an ``alternate form''. +For +.Cm c , +.Cm d , +and +.Cm s , +formats, this option has no effect. For the +.Cm o +formats the precision of the number is increased to force the first +character of the output string to a zero. For the +.Cm x +.Pq Cm X +format, a non-zero result has the string +.Li 0x +.Pq Li 0X +prepended to it. For +.Cm e , +.Cm E , +.Cm f , +.Cm g , +and +.Cm G , +formats, the result will always contain a decimal point, even if no +digits follow the point (normally, a decimal point only appears in the +results of those formats if a digit follows the decimal point). For +.Cm g +and +.Cm G +formats, trailing zeros are not removed from the result as they +would otherwise be; +.It Cm \&\- +A minus sign `\-' which specifies +.Em left adjustment +of the output in the indicated field; +.It Cm \&+ +A `+' character specifying that there should always be +a sign placed before the number when using signed formats. +.It Sq \&\ \& +A space specifying that a blank should be left before a positive number +for a signed format. A `+' overrides a space if both are used; +.It Cm \&0 +A zero `0' character indicating that zero-padding should be used +rather than blank-padding. A `\-' overrides a `0' if both are used; +.El +.It "Field Width:" +An optional digit string specifying a +.Em field width ; +if the output string 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 (note that a leading zero +is a flag, but an embedded zero is part of a field width); +.It Precision: +An optional period, +.Sq Cm \&.\& , +followed by an optional digit string giving a +.Em precision +which specifies the number of digits to appear after the decimal point, +for +.Cm e +and +.Cm f +formats, or the maximum number of characters to be printed +from a string; if the digit string is missing, the precision is treated +as zero; +.It Format: +A character which indicates the type of format to use (one of +.Cm diouxXfwEgGcs ) . +.El +.Pp +A field width or precision may be +.Sq Cm \&* +instead of a digit string. +In this case an +.Ar argument +supplies the field width or precision. +.Pp +The format characters and their meanings are: +.Bl -tag -width Fl +.It Cm diouXx +The +.Ar argument +is printed as a signed decimal (d or i), unsigned decimal, unsigned octal, +or unsigned hexadecimal (X or x), respectively. +.It Cm f +The +.Ar argument +is printed in the style `[\-]ddd.ddd' where the number of d's +after the decimal point is equal to the precision specification for +the argument. +If the precision is missing, 6 digits are given; if the precision +is explicitly 0, no digits and no decimal point are printed. +.It Cm eE +The +.Ar argument +is printed in the style +.Cm e +.`[-]d.ddd Ns \(+-dd\' +where there +is one digit before the decimal point and the number after is equal to +the precision specification for the argument; when the precision is +missing, 6 digits are produced. +An upper-case E is used for an `E' format. +.It Cm gG +The +.Ar argument +is printed in style +.Cm f +or in style +.Cm e +.Pq Cm E +whichever gives full precision in minimum space. +.It Cm c +The first character of +.Ar argument +is printed. +.It Cm s +Characters from the string +.Ar argument +are printed until the end is reached or until the number of characters +indicated by the precision specification is reached; however if the +precision is 0 or missing, all characters in the string are printed. +.It Cm \&% +Print a `%'; no argument is used. +.El +.Pp +In no case does a non-existent or small field width cause truncation of +a field; padding takes place only if the specified field width exceeds +the actual width. +.Sh RETURN VALUES +.Nm Printf +exits 0 on success, 1 on failure. +.Sh SEE ALSO +.Xr printf 3 +.Sh HISTORY +The +.Nm printf +command appeared in +.Bx 4.3 Reno . +It is modeled +after the standard library function, +.Xr printf 3 . +.Sh BUGS +Since the number is translated from +.Tn ASCII +to floating-point, and +then back again, floating-point precision may be lost. +.Pp +.Tn ANSI +hexadecimal character constants were deliberately not provided. diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c new file mode 100644 index 000000000000..a64e4d4c4d2c --- /dev/null +++ b/usr.bin/printf/printf.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)printf.c 5.9 (Berkeley) 6/1/90"; +#endif /* not lint */ + +#include <sys/types.h> +#include <stdio.h> + +#define PF(f, func) { \ + if (fieldwidth) \ + if (precision) \ + (void)printf(f, fieldwidth, precision, func); \ + else \ + (void)printf(f, fieldwidth, func); \ + else if (precision) \ + (void)printf(f, precision, func); \ + else \ + (void)printf(f, func); \ +} + +char **gargv; + +main(argc, argv) + int argc; + char **argv; +{ + static char *skip1, *skip2; + register char *format, *fmt, *start; + register int end, fieldwidth, precision; + char convch, nextch, *getstr(), *index(), *mklong(); + double getdouble(); + long getlong(); + + if (argc < 2) { + fprintf(stderr, "usage: printf format [arg ...]\n"); + exit(1); + } + + /* + * Basic algorithm is to scan the format string for conversion + * specifications -- once one is found, find out if the field + * width or precision is a '*'; if it is, gather up value. Note, + * format strings are reused as necessary to use up the provided + * arguments, arguments of zero/null string are provided to use + * up the format string. + */ + skip1 = "#-+ 0"; + skip2 = "*0123456789"; + + escape(fmt = format = *++argv); /* backslash interpretation */ + gargv = ++argv; + for (;;) { + end = 0; + /* find next format specification */ +next: for (start = fmt;; ++fmt) { + if (!*fmt) { + /* avoid infinite loop */ + if (end == 1) { + fprintf(stderr, + "printf: missing format character.\n"); + exit(1); + } + end = 1; + if (fmt > start) + (void)printf("%s", start); + if (!*gargv) + exit(0); + fmt = format; + goto next; + } + /* %% prints a % */ + if (*fmt == '%') { + if (*++fmt != '%') + break; + *fmt++ = '\0'; + (void)printf("%s", start); + goto next; + } + } + + /* skip to field width */ + for (; index(skip1, *fmt); ++fmt); + fieldwidth = *fmt == '*' ? getint() : 0; + + /* skip to possible '.', get following precision */ + for (; index(skip2, *fmt); ++fmt); + if (*fmt == '.') + ++fmt; + precision = *fmt == '*' ? getint() : 0; + + /* skip to conversion char */ + for (; index(skip2, *fmt); ++fmt); + if (!*fmt) { + fprintf(stderr, "printf: missing format character.\n"); + exit(1); + } + + convch = *fmt; + nextch = *++fmt; + *fmt = '\0'; + switch(convch) { + case 'c': { + char p = getchr(); + PF(start, p); + break; + } + case 's': { + char *p = getstr(); + PF(start, p); + break; + } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + char *f = mklong(start, convch); + long p = getlong(); + PF(f, p); + break; + } + case 'e': case 'E': case 'f': case 'g': case 'G': { + double p = getdouble(); + PF(start, p); + break; + } + default: + fprintf(stderr, "printf: illegal format character.\n"); + exit(1); + } + *fmt = nextch; + } + /* NOTREACHED */ +} + +char * +mklong(str, ch) + char *str, ch; +{ + int len; + char *copy, *malloc(); + + len = strlen(str) + 2; + if (!(copy = malloc((u_int)len))) { /* never freed; XXX */ + fprintf(stderr, "printf: out of memory.\n"); + exit(1); + } + bcopy(str, copy, len - 3); + copy[len - 3] = 'l'; + copy[len - 2] = ch; + copy[len - 1] = '\0'; + return(copy); +} + +escape(fmt) + register char *fmt; +{ + register char *store; + register int value, c; + + for (store = fmt; c = *fmt; ++fmt, ++store) { + if (c != '\\') { + *store = c; + continue; + } + switch (*++fmt) { + case '\0': /* EOS, user error */ + *store = '\\'; + *++store = '\0'; + return; + case '\\': /* backslash */ + case '\'': /* single quote */ + *store = *fmt; + break; + case 'a': /* bell/alert */ + *store = '\7'; + break; + case 'b': /* backspace */ + *store = '\b'; + break; + case 'f': /* form-feed */ + *store = '\f'; + break; + case 'n': /* newline */ + *store = '\n'; + break; + case 'r': /* carriage-return */ + *store = '\r'; + break; + case 't': /* horizontal tab */ + *store = '\t'; + break; + case 'v': /* vertical tab */ + *store = '\13'; + break; + /* octal constant */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + for (c = 3, value = 0; + c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { + value <<= 3; + value += *fmt - '0'; + } + --fmt; + *store = value; + break; + default: + *store = *fmt; + break; + } + } + *store = '\0'; +} + +getchr() +{ + if (!*gargv) + return((int)'\0'); + return((int)**gargv++); +} + +char * +getstr() +{ + if (!*gargv) + return(""); + return(*gargv++); +} + +static char *number = "+-.0123456789"; +getint() +{ + if (!*gargv) + return(0); + if (index(number, **gargv)) + return(atoi(*gargv++)); + return(asciicode()); +} + +long +getlong() +{ + long atol(); + + if (!*gargv) + return((long)0); + if (index(number, **gargv)) + return(strtol(*gargv++, (char **)NULL, 0)); + return((long)asciicode()); +} + +double +getdouble() +{ + double atof(); + + if (!*gargv) + return((double)0); + if (index(number, **gargv)) + return(atof(*gargv++)); + return((double)asciicode()); +} + +asciicode() +{ + register char ch; + + ch = **gargv; + if (ch == '\'' || ch == '"') + ch = (*gargv)[1]; + ++gargv; + return(ch); +} |
