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