blob: e2f7458abe6fa698ba8cbfb143d956ad82d86259 [file] [log] [blame]
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001From 0933ca6251808f856b92b0ce8da8696d5febc333 Mon Sep 17 00:00:00 2001
2From: Emil Renner Berthing <systemd@esmil.dk>
3Date: Mon, 23 Oct 2017 10:41:39 -0700
4Subject: [PATCH 01/12] add fallback parse_printf_format implementation
5
6Signed-off-by: Emil Renner Berthing <systemd@esmil.dk>
7Signed-off-by: Khem Raj <raj.khem@gmail.com>
8---
9Upstream-Status: Pending
10
11 Makefile.am | 4 +
12 configure.ac | 2 +
13 src/basic/parse-printf-format.c | 273 ++++++++++++++++++++++++++++++++++++++++
14 src/basic/parse-printf-format.h | 57 +++++++++
15 src/basic/stdio-util.h | 2 +-
16 src/journal/journal-send.c | 2 +-
17 6 files changed, 338 insertions(+), 2 deletions(-)
18 create mode 100644 src/basic/parse-printf-format.c
19 create mode 100644 src/basic/parse-printf-format.h
20
21diff --git a/Makefile.am b/Makefile.am
22index 692d7bb95..3cc8f3451 100644
23--- a/Makefile.am
24+++ b/Makefile.am
25@@ -997,6 +997,10 @@ libbasic_la_SOURCES = \
26 src/basic/journal-importer.h \
27 src/basic/journal-importer.c
28
29+if !HAVE_PRINTF_H
30+libbasic_la_SOURCES += src/basic/parse-printf-format.c
31+endif
32+
33 nodist_libbasic_la_SOURCES = \
34 src/basic/errno-from-name.h \
35 src/basic/errno-to-name.h \
36diff --git a/configure.ac b/configure.ac
37index 60e7df5ee..efcdc6c16 100644
38--- a/configure.ac
39+++ b/configure.ac
40@@ -308,8 +308,10 @@ AC_CHECK_HEADERS([uchar.h], [], [])
41 AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([*** POSIX caps headers not found])])
42 AC_CHECK_HEADERS([linux/btrfs.h], [], [])
43 AC_CHECK_HEADERS([linux/memfd.h], [], [])
44+AC_CHECK_HEADERS([printf.h], [], [])
45 AC_CHECK_HEADERS([linux/vm_sockets.h], [], [], [#include <sys/socket.h>])
46
47+AM_CONDITIONAL(HAVE_PRINTF_H, [test "x$ac_cv_header_printf_h" = xyes])
48 # unconditionally pull-in librt with old glibc versions
49 AC_SEARCH_LIBS([clock_gettime], [rt], [], [])
50
51diff --git a/src/basic/parse-printf-format.c b/src/basic/parse-printf-format.c
52new file mode 100644
53index 000000000..49437e544
54--- /dev/null
55+++ b/src/basic/parse-printf-format.c
56@@ -0,0 +1,273 @@
57+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
58+
59+/***
60+ This file is part of systemd.
61+
62+ Copyright 2014 Emil Renner Berthing <systemd@esmil.dk>
63+
64+ With parts from the musl C library
65+ Copyright 2005-2014 Rich Felker, et al.
66+
67+ systemd is free software; you can redistribute it and/or modify it
68+ under the terms of the GNU Lesser General Public License as published by
69+ the Free Software Foundation; either version 2.1 of the License, or
70+ (at your option) any later version.
71+
72+ systemd is distributed in the hope that it will be useful, but
73+ WITHOUT ANY WARRANTY; without even the implied warranty of
74+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
75+ Lesser General Public License for more details.
76+
77+ You should have received a copy of the GNU Lesser General Public License
78+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
79+***/
80+
81+#include <stddef.h>
82+#include <string.h>
83+
84+#include "parse-printf-format.h"
85+
86+static const char *consume_nonarg(const char *fmt)
87+{
88+ do {
89+ if (*fmt == '\0')
90+ return fmt;
91+ } while (*fmt++ != '%');
92+ return fmt;
93+}
94+
95+static const char *consume_num(const char *fmt)
96+{
97+ for (;*fmt >= '0' && *fmt <= '9'; fmt++)
98+ /* do nothing */;
99+ return fmt;
100+}
101+
102+static const char *consume_argn(const char *fmt, size_t *arg)
103+{
104+ const char *p = fmt;
105+ size_t val = 0;
106+
107+ if (*p < '1' || *p > '9')
108+ return fmt;
109+ do {
110+ val = 10*val + (*p++ - '0');
111+ } while (*p >= '0' && *p <= '9');
112+
113+ if (*p != '$')
114+ return fmt;
115+ *arg = val;
116+ return p+1;
117+}
118+
119+static const char *consume_flags(const char *fmt)
120+{
121+ while (1) {
122+ switch (*fmt) {
123+ case '#':
124+ case '0':
125+ case '-':
126+ case ' ':
127+ case '+':
128+ case '\'':
129+ case 'I':
130+ fmt++;
131+ continue;
132+ }
133+ return fmt;
134+ }
135+}
136+
137+enum state {
138+ BARE,
139+ LPRE,
140+ LLPRE,
141+ HPRE,
142+ HHPRE,
143+ BIGLPRE,
144+ ZTPRE,
145+ JPRE,
146+ STOP
147+};
148+
149+enum type {
150+ NONE,
151+ PTR,
152+ INT,
153+ UINT,
154+ ULLONG,
155+ LONG,
156+ ULONG,
157+ SHORT,
158+ USHORT,
159+ CHAR,
160+ UCHAR,
161+ LLONG,
162+ SIZET,
163+ IMAX,
164+ UMAX,
165+ PDIFF,
166+ UIPTR,
167+ DBL,
168+ LDBL,
169+ MAXTYPE
170+};
171+
172+static const short pa_types[MAXTYPE] = {
173+ [NONE] = PA_INT,
174+ [PTR] = PA_POINTER,
175+ [INT] = PA_INT,
176+ [UINT] = PA_INT,
177+ [ULLONG] = PA_INT | PA_FLAG_LONG_LONG,
178+ [LONG] = PA_INT | PA_FLAG_LONG,
179+ [ULONG] = PA_INT | PA_FLAG_LONG,
180+ [SHORT] = PA_INT | PA_FLAG_SHORT,
181+ [USHORT] = PA_INT | PA_FLAG_SHORT,
182+ [CHAR] = PA_CHAR,
183+ [UCHAR] = PA_CHAR,
184+ [LLONG] = PA_INT | PA_FLAG_LONG_LONG,
185+ [SIZET] = PA_INT | PA_FLAG_LONG,
186+ [IMAX] = PA_INT | PA_FLAG_LONG_LONG,
187+ [UMAX] = PA_INT | PA_FLAG_LONG_LONG,
188+ [PDIFF] = PA_INT | PA_FLAG_LONG_LONG,
189+ [UIPTR] = PA_INT | PA_FLAG_LONG,
190+ [DBL] = PA_DOUBLE,
191+ [LDBL] = PA_DOUBLE | PA_FLAG_LONG_DOUBLE
192+};
193+
194+#define S(x) [(x)-'A']
195+#define E(x) (STOP + (x))
196+
197+static const unsigned char states[]['z'-'A'+1] = {
198+ { /* 0: bare types */
199+ S('d') = E(INT), S('i') = E(INT),
200+ S('o') = E(UINT),S('u') = E(UINT),S('x') = E(UINT), S('X') = E(UINT),
201+ S('e') = E(DBL), S('f') = E(DBL), S('g') = E(DBL), S('a') = E(DBL),
202+ S('E') = E(DBL), S('F') = E(DBL), S('G') = E(DBL), S('A') = E(DBL),
203+ S('c') = E(CHAR),S('C') = E(INT),
204+ S('s') = E(PTR), S('S') = E(PTR), S('p') = E(UIPTR),S('n') = E(PTR),
205+ S('m') = E(NONE),
206+ S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
207+ S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE
208+ }, { /* 1: l-prefixed */
209+ S('d') = E(LONG), S('i') = E(LONG),
210+ S('o') = E(ULONG),S('u') = E(ULONG),S('x') = E(ULONG),S('X') = E(ULONG),
211+ S('e') = E(DBL), S('f') = E(DBL), S('g') = E(DBL), S('a') = E(DBL),
212+ S('E') = E(DBL), S('F') = E(DBL), S('G') = E(DBL), S('A') = E(DBL),
213+ S('c') = E(INT), S('s') = E(PTR), S('n') = E(PTR),
214+ S('l') = LLPRE
215+ }, { /* 2: ll-prefixed */
216+ S('d') = E(LLONG), S('i') = E(LLONG),
217+ S('o') = E(ULLONG),S('u') = E(ULLONG),
218+ S('x') = E(ULLONG),S('X') = E(ULLONG),
219+ S('n') = E(PTR)
220+ }, { /* 3: h-prefixed */
221+ S('d') = E(SHORT), S('i') = E(SHORT),
222+ S('o') = E(USHORT),S('u') = E(USHORT),
223+ S('x') = E(USHORT),S('X') = E(USHORT),
224+ S('n') = E(PTR),
225+ S('h') = HHPRE
226+ }, { /* 4: hh-prefixed */
227+ S('d') = E(CHAR), S('i') = E(CHAR),
228+ S('o') = E(UCHAR),S('u') = E(UCHAR),
229+ S('x') = E(UCHAR),S('X') = E(UCHAR),
230+ S('n') = E(PTR)
231+ }, { /* 5: L-prefixed */
232+ S('e') = E(LDBL),S('f') = E(LDBL),S('g') = E(LDBL), S('a') = E(LDBL),
233+ S('E') = E(LDBL),S('F') = E(LDBL),S('G') = E(LDBL), S('A') = E(LDBL),
234+ S('n') = E(PTR)
235+ }, { /* 6: z- or t-prefixed (assumed to be same size) */
236+ S('d') = E(PDIFF),S('i') = E(PDIFF),
237+ S('o') = E(SIZET),S('u') = E(SIZET),
238+ S('x') = E(SIZET),S('X') = E(SIZET),
239+ S('n') = E(PTR)
240+ }, { /* 7: j-prefixed */
241+ S('d') = E(IMAX), S('i') = E(IMAX),
242+ S('o') = E(UMAX), S('u') = E(UMAX),
243+ S('x') = E(UMAX), S('X') = E(UMAX),
244+ S('n') = E(PTR)
245+ }
246+};
247+
248+size_t parse_printf_format(const char *fmt, size_t n, int *types)
249+{
250+ size_t i = 0;
251+ size_t last = 0;
252+
253+ memset(types, 0, n);
254+
255+ while (1) {
256+ size_t arg;
257+ unsigned int state;
258+
259+ fmt = consume_nonarg(fmt);
260+ if (*fmt == '\0')
261+ break;
262+ if (*fmt == '%') {
263+ fmt++;
264+ continue;
265+ }
266+ arg = 0;
267+ fmt = consume_argn(fmt, &arg);
268+ /* flags */
269+ fmt = consume_flags(fmt);
270+ /* width */
271+ if (*fmt == '*') {
272+ size_t warg = 0;
273+ fmt = consume_argn(fmt+1, &warg);
274+ if (warg == 0)
275+ warg = ++i;
276+ if (warg > last)
277+ last = warg;
278+ if (warg <= n && types[warg-1] == NONE)
279+ types[warg-1] = INT;
280+ } else
281+ fmt = consume_num(fmt);
282+ /* precision */
283+ if (*fmt == '.') {
284+ fmt++;
285+ if (*fmt == '*') {
286+ size_t parg = 0;
287+ fmt = consume_argn(fmt+1, &parg);
288+ if (parg == 0)
289+ parg = ++i;
290+ if (parg > last)
291+ last = parg;
292+ if (parg <= n && types[parg-1] == NONE)
293+ types[parg-1] = INT;
294+ } else {
295+ if (*fmt == '-')
296+ fmt++;
297+ fmt = consume_num(fmt);
298+ }
299+ }
300+ /* length modifier and conversion specifier */
301+ state = BARE;
302+ do {
303+ unsigned char c = *fmt++;
304+
305+ if (c < 'A' || c > 'z')
306+ continue;
307+ state = states[state]S(c);
308+ if (state == 0)
309+ continue;
310+ } while (state < STOP);
311+
312+ if (state == E(NONE))
313+ continue;
314+
315+ if (arg == 0)
316+ arg = ++i;
317+ if (arg > last)
318+ last = arg;
319+ if (arg <= n)
320+ types[arg-1] = state - STOP;
321+ }
322+
323+ if (last > n)
324+ last = n;
325+ for (i = 0; i < last; i++)
326+ types[i] = pa_types[types[i]];
327+
328+ return last;
329+}
330diff --git a/src/basic/parse-printf-format.h b/src/basic/parse-printf-format.h
331new file mode 100644
332index 000000000..4371177b0
333--- /dev/null
334+++ b/src/basic/parse-printf-format.h
335@@ -0,0 +1,57 @@
336+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
337+
338+/***
339+ This file is part of systemd.
340+
341+ Copyright 2014 Emil Renner Berthing <systemd@esmil.dk>
342+
343+ With parts from the GNU C Library
344+ Copyright 1991-2014 Free Software Foundation, Inc.
345+
346+ systemd is free software; you can redistribute it and/or modify it
347+ under the terms of the GNU Lesser General Public License as published by
348+ the Free Software Foundation; either version 2.1 of the License, or
349+ (at your option) any later version.
350+
351+ systemd is distributed in the hope that it will be useful, but
352+ WITHOUT ANY WARRANTY; without even the implied warranty of
353+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
354+ Lesser General Public License for more details.
355+
356+ You should have received a copy of the GNU Lesser General Public License
357+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
358+***/
359+
360+#pragma once
361+
362+#include "config.h"
363+
364+#ifdef HAVE_PRINTF_H
365+#include <printf.h>
366+#else
367+
368+#include <stddef.h>
369+
370+enum { /* C type: */
371+ PA_INT, /* int */
372+ PA_CHAR, /* int, cast to char */
373+ PA_WCHAR, /* wide char */
374+ PA_STRING, /* const char *, a '\0'-terminated string */
375+ PA_WSTRING, /* const wchar_t *, wide character string */
376+ PA_POINTER, /* void * */
377+ PA_FLOAT, /* float */
378+ PA_DOUBLE, /* double */
379+ PA_LAST
380+};
381+
382+/* Flag bits that can be set in a type returned by `parse_printf_format'. */
383+#define PA_FLAG_MASK 0xff00
384+#define PA_FLAG_LONG_LONG (1 << 8)
385+#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
386+#define PA_FLAG_LONG (1 << 9)
387+#define PA_FLAG_SHORT (1 << 10)
388+#define PA_FLAG_PTR (1 << 11)
389+
390+size_t parse_printf_format(const char *fmt, size_t n, int *types);
391+
392+#endif /* HAVE_PRINTF_H */
393diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h
394index bd1144b4c..c9c95eb54 100644
395--- a/src/basic/stdio-util.h
396+++ b/src/basic/stdio-util.h
397@@ -19,12 +19,12 @@
398 along with systemd; If not, see <http://www.gnu.org/licenses/>.
399 ***/
400
401-#include <printf.h>
402 #include <stdarg.h>
403 #include <stdio.h>
404 #include <sys/types.h>
405
406 #include "macro.h"
407+#include "parse-printf-format.h"
408
409 #define xsprintf(buf, fmt, ...) \
410 assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough")
411diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
412index 440fba67c..0236c43c4 100644
413--- a/src/journal/journal-send.c
414+++ b/src/journal/journal-send.c
415@@ -19,7 +19,6 @@
416
417 #include <errno.h>
418 #include <fcntl.h>
419-#include <printf.h>
420 #include <stddef.h>
421 #include <sys/socket.h>
422 #include <sys/un.h>
423@@ -38,6 +37,7 @@
424 #include "stdio-util.h"
425 #include "string-util.h"
426 #include "util.h"
427+#include "parse-printf-format.h"
428
429 #define SNDBUF_SIZE (8*1024*1024)
430
431--
4322.14.2
433