Date: Thu, 7 Mar 2002 14:08:45 +1100 (EST) From: "Tim J. Robbins" <tim@robbins.dropbear.id.au> To: FreeBSD-gnats-submit@freebsd.org Subject: bin/35616: Patch to bring printf(1) up to POSIX.2 (1992) conformance Message-ID: <200203070308.g2738jh33226@descent.robbins.dropbear.id.au>
next in thread | raw e-mail | index | archive | help
>Number: 35616 >Category: bin >Synopsis: Patch to bring printf(1) up to POSIX.2 (1992) conformance >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Wed Mar 06 19:10:00 PST 2002 >Closed-Date: >Last-Modified: >Originator: Tim J. Robbins >Release: FreeBSD 4.5-STABLE i386 >Organization: >Environment: System: FreeBSD descent.robbins.dropbear.id.au 4.5-STABLE FreeBSD 4.5-STABLE #5: Sat Feb 16 18:56:18 EST 2002 tim@descent.robbins.dropbear.id.au:/usr/obj/usr/src/sys/DESCENT i386 >Description: FreeBSD's printf(1) command is not POSIX.2 conformant. The missing features are: - printf shouldn't bail out if a conversion fails, it should just keep processing them. - \c escape to immediately stop output (similar to echo's \c) - \0NNN should be allowed for octal character escapes (instead of just \NNN) - %b conversion, which is like %s but interprets \n \t etc. inside the string is missing. I believe this patch also brings printf(1) up to P1003.1-2001 conformance. >How-To-Repeat: $ printf %d A 65 (should write 0 and warn that it expected a number) $ printf %b "hello\n" printf: illegal format character b (should be equivalent to printf "hello\n") $ printf 'hello\n\cworld\n' hello cworld (should be "hello" and a newline) If you are trying to reproduce these problems, make sure you use /usr/bin/printf - my shell, ksh93, has a printf builtin. >Fix: Index: printf/printf.1 =================================================================== RCS file: /home/ncvs/src/usr.bin/printf/printf.1,v retrieving revision 1.19 diff -u -r1.19 printf.1 --- printf/printf.1 2002/01/16 14:55:18 1.19 +++ printf/printf.1 2002/03/07 02:55:11 @@ -61,7 +61,8 @@ .Ar arguments after the first are treated as strings if the corresponding format is either -.Cm c +.Cm c , +.Cm b or .Cm s ; otherwise it is evaluated as a C constant, with the following extensions: @@ -70,8 +71,8 @@ .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. +If the leading character is a single or double quote the value is the ASCII +code of the next character. .El .Pp The format string is reused as often as necessary to satisfy the @@ -80,7 +81,8 @@ string. .Pp Character escape sequences are in backslash notation as defined in the -.St -ansiC . +.St -ansiC , +with extensions. The characters and their meanings are as follows: .Pp @@ -89,6 +91,8 @@ Write a <bell> character. .It Cm \eb Write a <backspace> character. +.It Cm \ec +Ignore remaining characters in this string. .It Cm \ef Write a <form-feed> character. .It Cm \en @@ -104,6 +108,7 @@ .It Cm \e\e Write a backslash character. .It Cm \e Ns Ar num +.It Cm \e0 Ns Ar num Write an 8-bit character whose .Tn ASCII value is the 1-, 2-, or 3-digit @@ -186,7 +191,7 @@ as zero; .It Format: A character which indicates the type of format to use (one of -.Cm diouxXfwEgGcs ) . +.Cm diouxXfwEgGcsb ) . .El .Pp A field width or precision may be @@ -243,6 +248,11 @@ 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 b +As for +.Cm s , +but interpret character escapes in backslash notation in the string +.Ar argument . .It Cm \&% Print a `%'; no argument is used. .El @@ -256,8 +266,20 @@ the actual width. .Sh DIAGNOSTICS .Ex -std +.Sh COMPATIBILITY +The traditional +.Bx +behavior of converting arguments of numeric formats not beginning +with a digit to the ASCII code of the first characer is not supported. .Sh SEE ALSO +.Xr echo 1 , .Xr printf 3 +.Sh STANDARDS +The +.Nm +command is expected to be compatible with the +.St -p1003.2 +specification. .Sh HISTORY The .Nm Index: printf/printf.c =================================================================== RCS file: /home/ncvs/src/usr.bin/printf/printf.c,v retrieving revision 1.18 diff -u -r1.18 printf.c --- printf/printf.c 2001/12/03 21:17:45 1.18 +++ printf/printf.c 2002/03/07 02:55:12 @@ -89,7 +89,7 @@ } static int asciicode __P((void)); -static void escape __P((char *)); +static int escape __P((char *)); static int getchr __P((void)); static double getdouble __P((void)); static int getint __P((int *)); @@ -209,6 +209,19 @@ nextch = *++fmt; *fmt = '\0'; switch(convch) { + case 'b': { + char *p; + int getout; + + if ((p = strdup(getstr())) == NULL) + err(1, NULL); + getout = escape(p); + PF("%s", p); + free(p); + if (getout) + return (0); + break; + } case 'c': { char p; @@ -227,11 +240,10 @@ quad_t p; char *f; - if ((f = mklong(start, convch)) == NULL) - return (1); - if (getquad(&p)) - return (1); - PF(f, p); + if ((f = mklong(start, convch)) != NULL && + !getquad(&p)) { + PF(f, p); + } break; } case 'e': case 'E': case 'f': case 'g': case 'G': { @@ -280,7 +292,7 @@ return (copy); } -static void +static int escape(fmt) register char *fmt; { @@ -296,7 +308,7 @@ case '\0': /* EOS, user error */ *store = '\\'; *++store = '\0'; - return; + return (0); case '\\': /* backslash */ case '\'': /* single quote */ *store = *fmt; @@ -307,6 +319,9 @@ case 'b': /* backspace */ *store = '\b'; break; + case 'c': + *store = '\0'; + return (1); case 'f': /* form-feed */ *store = '\f'; break; @@ -325,7 +340,7 @@ /* octal constant */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - for (c = 3, value = 0; + for (c = *fmt == '0' ? 4 : 3, value = 0; c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { value <<= 3; value += *fmt - '0'; @@ -339,6 +354,7 @@ } } *store = '\0'; + return (0); } static int @@ -357,7 +373,6 @@ return (*gargv++); } -static const char *Number = "+-.0123456789"; static int getint(ip) int *ip; @@ -366,10 +381,8 @@ if (getquad(&val)) return (1); - if (val < INT_MIN || val > INT_MAX) { + if (val < INT_MIN || val > INT_MAX) warnx3("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } *ip = (int)val; return (0); } @@ -385,39 +398,51 @@ *lp = 0; return (0); } - if (strchr(Number, **gargv)) { - errno = 0; - val = strtoq(*gargv, &ep, 0); - if (*ep != '\0') { - warnx2("%s: illegal number", *gargv, NULL); - return (1); - } - if (errno == ERANGE) - if (val == QUAD_MAX) { - warnx3("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - if (val == QUAD_MIN) { - warnx3("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - *lp = val; + if (**gargv == '"' || **gargv == '\'') { + *lp = (quad_t)asciicode(); ++gargv; return (0); } - *lp = (long)asciicode(); + + errno = 0; + val = strtoq(*gargv, &ep, 0); + if (ep == *gargv) + warnx2("%s: expected numeric value", *gargv, NULL); + else if (*ep != '\0') + warnx2("%s: not completely converted", *gargv, NULL); + if (errno == ERANGE) + warnx3("%s: %s", *gargv, strerror(ERANGE)); + *lp = val; + ++gargv; return (0); } static double getdouble() { + double val; + char *ep; + if (!*gargv) return ((double)0); - if (strchr(Number, **gargv)) - return (atof(*gargv++)); - return ((double)asciicode()); + + if (**gargv == '"' || **gargv == '\'') { + val = (double)asciicode(); + ++gargv; + return (val); + } + + errno = 0; + val = strtod(*gargv, &ep); + if (ep == *gargv) + warnx2("%s: expected numeric value", *gargv, NULL); + else if (*ep != '\0') + warnx2("%s: not completely converted", *gargv, NULL); + if (errno == ERANGE) + warnx3("%s: %s", *gargv, strerror(ERANGE)); + ++gargv; + return (val); } static int >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200203070308.g2738jh33226>