Skip to content

Commit b0fec46

Browse files
committed
printf(1): implement '%q'
1 parent 29a4296 commit b0fec46

3 files changed

Lines changed: 332 additions & 17 deletions

File tree

‎patches/src.freebsd.patch‎

Lines changed: 201 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5645,12 +5645,192 @@
56455645
.It Cm \e\'
56465646
Write a <single quote> character.
56475647
.It Cm \e\e
5648+
@@ -290,6 +298,11 @@
5649+
stops further output from this
5650+
.Nm
5651+
invocation.
5652+
+.It Cm q
5653+
+As for
5654+
+.Cm s ,
5655+
+but print in a format that can be reused as shell input, escaping
5656+
+non-printable characters with the POSIX `$''' syntax.
5657+
.It Cm n$
5658+
Allows reordering of the output according to
5659+
.Ar argument .
56485660
--- src.orig/coreutils/printf/printf.c
56495661
+++ src.freebsd/coreutils/printf/printf.c
5650-
@@ -506,6 +506,24 @@
5662+
@@ -44,6 +44,7 @@
5663+
#include <inttypes.h>
5664+
#include <limits.h>
5665+
#include <locale.h>
5666+
+#include <stdbool.h>
5667+
#include <stdio.h>
5668+
#include <stdlib.h>
5669+
#include <string.h>
5670+
@@ -71,6 +72,7 @@
5671+
static int asciicode(void);
5672+
static char *printf_doformat(char *, int *);
5673+
static int escape(char *, int, size_t *);
5674+
+static char *unescape(const char *, bool *);
5675+
static int getchr(void);
5676+
static int getfloating(long double *, int);
5677+
static int getint(int *);
5678+
@@ -355,19 +357,26 @@
5679+
5680+
*fmt = '\0';
5681+
switch (convch) {
5682+
- case 'b': {
5683+
+ case 'b':
5684+
+ case 'q': {
5685+
size_t len;
5686+
char *p;
5687+
- int getout;
5688+
+ int getout = 0;
5689+
+ bool skipesc = false;
5690+
5691+
- /* Convert "b" to "s" for output. */
5692+
+ /* Convert "b" or "q" to "s" for output. */
5693+
start[strlen(start) - 1] = 's';
5694+
- if ((p = strdup(getstr())) == NULL) {
5695+
+ if (convch == 'q')
5696+
+ p = unescape(getstr(), &skipesc);
5697+
+ else
5698+
+ p = strdup(getstr());
5699+
+ if (p == NULL) {
5700+
warnx("%s", strerror(ENOMEM));
5701+
return (NULL);
5702+
}
5703+
- getout = escape(p, 0, &len);
5704+
- PF(start, p);
5705+
+ if (convch == 'b')
5706+
+ getout = escape(p, 0, &len);
5707+
+ PF(start, skipesc ? (p + 2) : p);
5708+
/* Restore format for next loop. */
5709+
5710+
free(p);
5711+
@@ -456,6 +465,117 @@
5712+
return (copy);
5713+
}
5714+
5715+
+static char *
5716+
+unescape(const char *str, bool *skipesc)
5717+
+{
5718+
+ /* start with a conservative buffer; this is for $'' + nul */
5719+
+ size_t bsz = 4;
5720+
+ size_t cap = strlen(str) + 32;
5721+
+ char *buf = malloc(cap), *p = buf;
5722+
+
5723+
+ if (!buf)
5724+
+ return NULL;
5725+
+
5726+
+ /* at first assume we won't be escaping */
5727+
+ *skipesc = true;
5728+
+ /* put this at the beginning in case we end up needing it */
5729+
+ *p++ = '$';
5730+
+ *p++ = '\'';
5731+
+
5732+
+ while (*str) {
5733+
+ if ((cap - bsz) < 4) {
5734+
+ char *nbuf;
5735+
+ /* space for longest escape */
5736+
+ cap *= 2;
5737+
+ nbuf = realloc(buf, cap);
5738+
+ if (!nbuf) {
5739+
+ free(buf);
5740+
+ return NULL;
5741+
+ }
5742+
+ buf = nbuf;
5743+
+ }
5744+
+ /* preliminary backslash */
5745+
+ *p++ = '\\';
5746+
+ switch (*str) {
5747+
+ case '\\':
5748+
+ case '\'':
5749+
+ case '$':
5750+
+ case '&':
5751+
+ case '*':
5752+
+ case '?':
5753+
+ case '|':
5754+
+ case '~':
5755+
+ case '^':
5756+
+ case ';':
5757+
+ case '`':
5758+
+ case ' ':
5759+
+ case '(':
5760+
+ case ')':
5761+
+ case '<':
5762+
+ case '>':
5763+
+ case '{':
5764+
+ case '}':
5765+
+ case '[':
5766+
+ case ']':
5767+
+ /* these get backslashed, but don't cause use of $'' */
5768+
+ *p++ = *str++;
5769+
+ continue;
5770+
+ case '\0':
5771+
+ *p++ = '0';
5772+
+ break;
5773+
+ case '\a':
5774+
+ *p++ = 'a';
5775+
+ break;
5776+
+ case '\b':
5777+
+ *p++ = 'b';
5778+
+ break;
5779+
+ case '\f':
5780+
+ *p++ = 'f';
5781+
+ break;
5782+
+ case '\n':
5783+
+ *p++ = 'n';
5784+
+ break;
5785+
+ case '\r':
5786+
+ *p++ = 'r';
5787+
+ break;
5788+
+ case '\t':
5789+
+ *p++ = 't';
5790+
+ break;
5791+
+ case '\v':
5792+
+ *p++ = 'v';
5793+
+ break;
5794+
+ default:
5795+
+ /* anything printable not covered above is not special
5796+
+ * to the shell and can just go in the string verbatim
5797+
+ */
5798+
+ if (isprint(*str)) {
5799+
+ p[-1] = *str++;
5800+
+ continue;
5801+
+ }
5802+
+ /* if we reach here, turn the character into an octal
5803+
+ * escape sequence, then take the escape path
5804+
+ */
5805+
+ *p++ = (*str >> 6) & 0x7;
5806+
+ *p++ = (*str >> 3) & 0x7;
5807+
+ *p++ = (*str >> 0) & 0x7;
5808+
+ break;
5809+
+ }
5810+
+ /* if we reach here, we end up using $''; the escape sequence
5811+
+ * is already in the result buffer, so just finish up here
5812+
+ */
5813+
+ *skipesc = false;
5814+
+ ++str;
5815+
+ }
5816+
+
5817+
+ /* if we did escaping, do the termination */
5818+
+ if (!*skipesc)
5819+
+ *p++ = '\'';
5820+
+ /* in any case, put in a null terminator */
5821+
+ *p++ = '\0';
5822+
+
5823+
+ return buf;
5824+
+}
5825+
+
5826+
static int
5827+
escape(char *fmt, int percent, size_t *len)
5828+
{
5829+
@@ -505,6 +625,24 @@
5830+
break;
56515831
case 'v': /* vertical tab */
56525832
*store = '\v';
5653-
break;
5833+
+ break;
56545834
+ case 'x': /* hexadecimal constant */
56555835
+ if (!percent) {
56565836
+ *store = 'x';
@@ -5668,10 +5848,9 @@
56685848
+ }
56695849
+ --fmt;
56705850
+ *store = (char)value;
5671-
+ break;
5851+
break;
56725852
/* octal constant */
56735853
case '0': case '1': case '2': case '3':
5674-
case '4': case '5': case '6': case '7':
56755854
--- src.orig/coreutils/pwd/pwd.c
56765855
+++ src.freebsd/coreutils/pwd/pwd.c
56775856
@@ -29,6 +29,7 @@
@@ -9688,31 +9867,33 @@
96889867
+#endif
96899868
--- src.orig/diffutils/diff/diffdir.c
96909869
+++ src.freebsd/diffutils/diff/diffdir.c
9691-
@@ -20,6 +20,7 @@
9870+
@@ -20,8 +20,8 @@
96929871
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
96939872
*/
96949873

96959874
+#include <sys/cdefs.h>
96969875
#include <sys/stat.h>
9697-
#include <sys/tree.h>
9876+
-#include <sys/tree.h>
96989877

9699-
@@ -43,6 +44,7 @@
9878+
#include <dirent.h>
9879+
#include <err.h>
9880+
@@ -43,6 +43,7 @@
97009881

97019882
#define d_status d_type /* we need to store status for -l */
97029883

97039884
+#if 0
97049885
struct inode {
97059886
dev_t dev;
97069887
ino_t ino;
9707-
@@ -97,6 +99,7 @@
9888+
@@ -97,6 +98,7 @@
97089889
errno = serrno;
97099890
return (-1);
97109891
}
97119892
+#endif
97129893

97139894
/*
97149895
* Diff directory traversal. Will be called recursively if -r was specified.
9715-
@@ -118,22 +121,26 @@
9896+
@@ -118,22 +120,26 @@
97169897
status |= 2;
97179898
return;
97189899
}
@@ -9744,7 +9925,7 @@
97449925
if (pos == -1) {
97459926
if (errno == ENOENT && (Nflag || Pflag)) {
97469927
pos = 0;
9747-
@@ -145,7 +152,7 @@
9928+
@@ -145,7 +151,7 @@
97489929
dp1 = dirp1;
97499930
edp1 = dirp1 + pos;
97509931

@@ -9753,7 +9934,7 @@
97539934
if (pos == -1) {
97549935
if (errno == ENOENT && Nflag) {
97559936
pos = 0;
9756-
@@ -165,18 +172,6 @@
9937+
@@ -165,18 +171,6 @@
97579938
dp1++;
97589939
while (dp2 != edp2 && strcmp((*dp2)->d_name, start) < 0)
97599940
dp2++;
@@ -10931,6 +11112,15 @@
1093111112
case 'U': /* uid numeric */
1093211113
fprintf(fout, "%d", sp->st_uid);
1093311114
break;
11115+
@@ -238,7 +245,7 @@
11116+
(float)sp->st_blocks * 512 / (float)sp->st_size);
11117+
break;
11118+
case 'd': /* Depth in tree */
11119+
- fprintf(fout, "%ld", entry->fts_level);
11120+
+ fprintf(fout, "%ld", (long)entry->fts_level);
11121+
break;
11122+
case 'D': /* device number */
11123+
fprintf(fout, "%ju", (uintmax_t)sp->st_dev);
1093411124
@@ -298,9 +305,6 @@
1093511125
case S_IFSOCK:
1093611126
putc('s', fout);

‎src.freebsd/coreutils/printf/printf.1‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ and that an additional escape sequence
298298
stops further output from this
299299
.Nm
300300
invocation.
301+
.It Cm q
302+
As for
303+
.Cm s ,
304+
but print in a format that can be reused as shell input, escaping
305+
non-printable characters with the POSIX `$''' syntax.
301306
.It Cm n$
302307
Allows reordering of the output according to
303308
.Ar argument .

0 commit comments

Comments
 (0)