blob: 2090d81dc39acc071479220845d513fe99e519af [file] [log] [blame]
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001From 383e85e15f16a46aac925aa439b8b60f58b40aa6 Mon Sep 17 00:00:00 2001
William A. Kennington IIIac69b482021-06-02 12:28:27 -07002From: Alexander Kanavin <alex.kanavin@gmail.com>
3Date: Sat, 22 May 2021 20:26:24 +0200
Andrew Geisslerd159c7f2021-09-02 21:05:58 -05004Subject: [PATCH] add fallback parse_printf_format implementation
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08005
6Upstream-Status: Inappropriate [musl specific]
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>
Brad Bishopa34c0302019-09-23 22:34:48 -040011[rebased for systemd 243]
12Signed-off-by: Scott Murray <scott.murray@konsulko.com>
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080013---
William A. Kennington IIIac69b482021-06-02 12:28:27 -070014 meson.build | 1 +
15 src/basic/meson.build | 5 +
16 src/basic/parse-printf-format.c | 273 +++++++++++++++++++++++
17 src/basic/parse-printf-format.h | 57 +++++
18 src/basic/stdio-util.h | 2 +-
19 src/libsystemd/sd-journal/journal-send.c | 2 +-
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080020 6 files changed, 338 insertions(+), 2 deletions(-)
21 create mode 100644 src/basic/parse-printf-format.c
22 create mode 100644 src/basic/parse-printf-format.h
23
Andrew Geisslerd1e89492021-02-12 15:35:20 -060024--- a/meson.build
25+++ b/meson.build
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050026@@ -755,6 +755,7 @@ endif
Brad Bishopa34c0302019-09-23 22:34:48 -040027 foreach header : ['crypt.h',
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080028 'linux/memfd.h',
29 'linux/vm_sockets.h',
30+ 'printf.h',
31 'sys/auxv.h',
Patrick Williams8e7b46e2023-05-01 14:19:06 -050032 'threads.h',
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080033 'valgrind/memcheck.h',
Andrew Geisslerd1e89492021-02-12 15:35:20 -060034--- a/src/basic/meson.build
35+++ b/src/basic/meson.build
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050036@@ -173,6 +173,11 @@ endforeach
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080037
Brad Bishop19323692019-04-05 15:28:33 -040038 basic_sources += generated_gperf_headers
William A. Kennington IIIac69b482021-06-02 12:28:27 -070039
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080040+if conf.get('HAVE_PRINTF_H') != 1
41+ basic_sources += [files('parse-printf-format.c')]
42+endif
43+
William A. Kennington IIIac69b482021-06-02 12:28:27 -070044+
45 ############################################################
46
47 arch_list = [
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080048--- /dev/null
Andrew Geisslerd1e89492021-02-12 15:35:20 -060049+++ b/src/basic/parse-printf-format.c
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080050@@ -0,0 +1,273 @@
51+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
52+
53+/***
54+ This file is part of systemd.
55+
56+ Copyright 2014 Emil Renner Berthing <systemd@esmil.dk>
57+
58+ With parts from the musl C library
59+ Copyright 2005-2014 Rich Felker, et al.
60+
61+ systemd is free software; you can redistribute it and/or modify it
62+ under the terms of the GNU Lesser General Public License as published by
63+ the Free Software Foundation; either version 2.1 of the License, or
64+ (at your option) any later version.
65+
66+ systemd is distributed in the hope that it will be useful, but
67+ WITHOUT ANY WARRANTY; without even the implied warranty of
68+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
69+ Lesser General Public License for more details.
70+
71+ You should have received a copy of the GNU Lesser General Public License
72+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
73+***/
74+
75+#include <stddef.h>
76+#include <string.h>
77+
78+#include "parse-printf-format.h"
79+
80+static const char *consume_nonarg(const char *fmt)
81+{
82+ do {
83+ if (*fmt == '\0')
84+ return fmt;
85+ } while (*fmt++ != '%');
86+ return fmt;
87+}
88+
89+static const char *consume_num(const char *fmt)
90+{
91+ for (;*fmt >= '0' && *fmt <= '9'; fmt++)
92+ /* do nothing */;
93+ return fmt;
94+}
95+
96+static const char *consume_argn(const char *fmt, size_t *arg)
97+{
98+ const char *p = fmt;
99+ size_t val = 0;
100+
101+ if (*p < '1' || *p > '9')
102+ return fmt;
103+ do {
104+ val = 10*val + (*p++ - '0');
105+ } while (*p >= '0' && *p <= '9');
106+
107+ if (*p != '$')
108+ return fmt;
109+ *arg = val;
110+ return p+1;
111+}
112+
113+static const char *consume_flags(const char *fmt)
114+{
115+ while (1) {
116+ switch (*fmt) {
117+ case '#':
118+ case '0':
119+ case '-':
120+ case ' ':
121+ case '+':
122+ case '\'':
123+ case 'I':
124+ fmt++;
125+ continue;
126+ }
127+ return fmt;
128+ }
129+}
130+
131+enum state {
132+ BARE,
133+ LPRE,
134+ LLPRE,
135+ HPRE,
136+ HHPRE,
137+ BIGLPRE,
138+ ZTPRE,
139+ JPRE,
140+ STOP
141+};
142+
143+enum type {
144+ NONE,
145+ PTR,
146+ INT,
147+ UINT,
148+ ULLONG,
149+ LONG,
150+ ULONG,
151+ SHORT,
152+ USHORT,
153+ CHAR,
154+ UCHAR,
155+ LLONG,
156+ SIZET,
157+ IMAX,
158+ UMAX,
159+ PDIFF,
160+ UIPTR,
161+ DBL,
162+ LDBL,
163+ MAXTYPE
164+};
165+
166+static const short pa_types[MAXTYPE] = {
167+ [NONE] = PA_INT,
168+ [PTR] = PA_POINTER,
169+ [INT] = PA_INT,
170+ [UINT] = PA_INT,
171+ [ULLONG] = PA_INT | PA_FLAG_LONG_LONG,
172+ [LONG] = PA_INT | PA_FLAG_LONG,
173+ [ULONG] = PA_INT | PA_FLAG_LONG,
174+ [SHORT] = PA_INT | PA_FLAG_SHORT,
175+ [USHORT] = PA_INT | PA_FLAG_SHORT,
176+ [CHAR] = PA_CHAR,
177+ [UCHAR] = PA_CHAR,
178+ [LLONG] = PA_INT | PA_FLAG_LONG_LONG,
179+ [SIZET] = PA_INT | PA_FLAG_LONG,
180+ [IMAX] = PA_INT | PA_FLAG_LONG_LONG,
181+ [UMAX] = PA_INT | PA_FLAG_LONG_LONG,
182+ [PDIFF] = PA_INT | PA_FLAG_LONG_LONG,
183+ [UIPTR] = PA_INT | PA_FLAG_LONG,
184+ [DBL] = PA_DOUBLE,
185+ [LDBL] = PA_DOUBLE | PA_FLAG_LONG_DOUBLE
186+};
187+
188+#define S(x) [(x)-'A']
189+#define E(x) (STOP + (x))
190+
191+static const unsigned char states[]['z'-'A'+1] = {
192+ { /* 0: bare types */
193+ S('d') = E(INT), S('i') = E(INT),
194+ S('o') = E(UINT),S('u') = E(UINT),S('x') = E(UINT), S('X') = E(UINT),
195+ S('e') = E(DBL), S('f') = E(DBL), S('g') = E(DBL), S('a') = E(DBL),
196+ S('E') = E(DBL), S('F') = E(DBL), S('G') = E(DBL), S('A') = E(DBL),
197+ S('c') = E(CHAR),S('C') = E(INT),
198+ S('s') = E(PTR), S('S') = E(PTR), S('p') = E(UIPTR),S('n') = E(PTR),
199+ S('m') = E(NONE),
200+ S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
201+ S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE
202+ }, { /* 1: l-prefixed */
203+ S('d') = E(LONG), S('i') = E(LONG),
204+ S('o') = E(ULONG),S('u') = E(ULONG),S('x') = E(ULONG),S('X') = E(ULONG),
205+ S('e') = E(DBL), S('f') = E(DBL), S('g') = E(DBL), S('a') = E(DBL),
206+ S('E') = E(DBL), S('F') = E(DBL), S('G') = E(DBL), S('A') = E(DBL),
207+ S('c') = E(INT), S('s') = E(PTR), S('n') = E(PTR),
208+ S('l') = LLPRE
209+ }, { /* 2: ll-prefixed */
210+ S('d') = E(LLONG), S('i') = E(LLONG),
211+ S('o') = E(ULLONG),S('u') = E(ULLONG),
212+ S('x') = E(ULLONG),S('X') = E(ULLONG),
213+ S('n') = E(PTR)
214+ }, { /* 3: h-prefixed */
215+ S('d') = E(SHORT), S('i') = E(SHORT),
216+ S('o') = E(USHORT),S('u') = E(USHORT),
217+ S('x') = E(USHORT),S('X') = E(USHORT),
218+ S('n') = E(PTR),
219+ S('h') = HHPRE
220+ }, { /* 4: hh-prefixed */
221+ S('d') = E(CHAR), S('i') = E(CHAR),
222+ S('o') = E(UCHAR),S('u') = E(UCHAR),
223+ S('x') = E(UCHAR),S('X') = E(UCHAR),
224+ S('n') = E(PTR)
225+ }, { /* 5: L-prefixed */
226+ S('e') = E(LDBL),S('f') = E(LDBL),S('g') = E(LDBL), S('a') = E(LDBL),
227+ S('E') = E(LDBL),S('F') = E(LDBL),S('G') = E(LDBL), S('A') = E(LDBL),
228+ S('n') = E(PTR)
229+ }, { /* 6: z- or t-prefixed (assumed to be same size) */
230+ S('d') = E(PDIFF),S('i') = E(PDIFF),
231+ S('o') = E(SIZET),S('u') = E(SIZET),
232+ S('x') = E(SIZET),S('X') = E(SIZET),
233+ S('n') = E(PTR)
234+ }, { /* 7: j-prefixed */
235+ S('d') = E(IMAX), S('i') = E(IMAX),
236+ S('o') = E(UMAX), S('u') = E(UMAX),
237+ S('x') = E(UMAX), S('X') = E(UMAX),
238+ S('n') = E(PTR)
239+ }
240+};
241+
242+size_t parse_printf_format(const char *fmt, size_t n, int *types)
243+{
244+ size_t i = 0;
245+ size_t last = 0;
246+
247+ memset(types, 0, n);
248+
249+ while (1) {
250+ size_t arg;
251+ unsigned int state;
252+
253+ fmt = consume_nonarg(fmt);
254+ if (*fmt == '\0')
255+ break;
256+ if (*fmt == '%') {
257+ fmt++;
258+ continue;
259+ }
260+ arg = 0;
261+ fmt = consume_argn(fmt, &arg);
262+ /* flags */
263+ fmt = consume_flags(fmt);
264+ /* width */
265+ if (*fmt == '*') {
266+ size_t warg = 0;
267+ fmt = consume_argn(fmt+1, &warg);
268+ if (warg == 0)
269+ warg = ++i;
270+ if (warg > last)
271+ last = warg;
272+ if (warg <= n && types[warg-1] == NONE)
273+ types[warg-1] = INT;
274+ } else
275+ fmt = consume_num(fmt);
276+ /* precision */
277+ if (*fmt == '.') {
278+ fmt++;
279+ if (*fmt == '*') {
280+ size_t parg = 0;
281+ fmt = consume_argn(fmt+1, &parg);
282+ if (parg == 0)
283+ parg = ++i;
284+ if (parg > last)
285+ last = parg;
286+ if (parg <= n && types[parg-1] == NONE)
287+ types[parg-1] = INT;
288+ } else {
289+ if (*fmt == '-')
290+ fmt++;
291+ fmt = consume_num(fmt);
292+ }
293+ }
294+ /* length modifier and conversion specifier */
295+ state = BARE;
296+ do {
297+ unsigned char c = *fmt++;
298+
299+ if (c < 'A' || c > 'z')
300+ continue;
301+ state = states[state]S(c);
302+ if (state == 0)
303+ continue;
304+ } while (state < STOP);
305+
306+ if (state == E(NONE))
307+ continue;
308+
309+ if (arg == 0)
310+ arg = ++i;
311+ if (arg > last)
312+ last = arg;
313+ if (arg <= n)
314+ types[arg-1] = state - STOP;
315+ }
316+
317+ if (last > n)
318+ last = n;
319+ for (i = 0; i < last; i++)
320+ types[i] = pa_types[types[i]];
321+
322+ return last;
323+}
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800324--- /dev/null
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600325+++ b/src/basic/parse-printf-format.h
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800326@@ -0,0 +1,57 @@
327+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
328+
329+/***
330+ This file is part of systemd.
331+
332+ Copyright 2014 Emil Renner Berthing <systemd@esmil.dk>
333+
334+ With parts from the GNU C Library
335+ Copyright 1991-2014 Free Software Foundation, Inc.
336+
337+ systemd is free software; you can redistribute it and/or modify it
338+ under the terms of the GNU Lesser General Public License as published by
339+ the Free Software Foundation; either version 2.1 of the License, or
340+ (at your option) any later version.
341+
342+ systemd is distributed in the hope that it will be useful, but
343+ WITHOUT ANY WARRANTY; without even the implied warranty of
344+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
345+ Lesser General Public License for more details.
346+
347+ You should have received a copy of the GNU Lesser General Public License
348+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
349+***/
350+
351+#pragma once
352+
353+#include "config.h"
354+
355+#if HAVE_PRINTF_H
356+#include <printf.h>
357+#else
358+
359+#include <stddef.h>
360+
361+enum { /* C type: */
362+ PA_INT, /* int */
363+ PA_CHAR, /* int, cast to char */
364+ PA_WCHAR, /* wide char */
365+ PA_STRING, /* const char *, a '\0'-terminated string */
366+ PA_WSTRING, /* const wchar_t *, wide character string */
367+ PA_POINTER, /* void * */
368+ PA_FLOAT, /* float */
369+ PA_DOUBLE, /* double */
370+ PA_LAST
371+};
372+
373+/* Flag bits that can be set in a type returned by `parse_printf_format'. */
374+#define PA_FLAG_MASK 0xff00
375+#define PA_FLAG_LONG_LONG (1 << 8)
376+#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
377+#define PA_FLAG_LONG (1 << 9)
378+#define PA_FLAG_SHORT (1 << 10)
379+#define PA_FLAG_PTR (1 << 11)
380+
381+size_t parse_printf_format(const char *fmt, size_t n, int *types);
382+
383+#endif /* HAVE_PRINTF_H */
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600384--- a/src/basic/stdio-util.h
385+++ b/src/basic/stdio-util.h
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500386@@ -1,12 +1,12 @@
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600387 /* SPDX-License-Identifier: LGPL-2.1-or-later */
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800388 #pragma once
389
390-#include <printf.h>
391 #include <stdarg.h>
392 #include <stdio.h>
393 #include <sys/types.h>
394
395 #include "macro.h"
396+#include "parse-printf-format.h"
397
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500398 _printf_(3, 4)
399 static inline char *snprintf_ok(char *buf, size_t len, const char *format, ...) {
William A. Kennington IIIac69b482021-06-02 12:28:27 -0700400--- a/src/libsystemd/sd-journal/journal-send.c
401+++ b/src/libsystemd/sd-journal/journal-send.c
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800402@@ -2,7 +2,6 @@
403
404 #include <errno.h>
405 #include <fcntl.h>
406-#include <printf.h>
407 #include <stddef.h>
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800408 #include <sys/un.h>
Andrew Geissler82c905d2020-04-13 13:39:40 -0500409 #include <unistd.h>
Andrew Geisslerd5838332022-05-27 11:33:10 -0500410@@ -25,6 +24,7 @@
Brad Bishopc342db32019-05-15 21:57:59 -0400411 #include "stdio-util.h"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800412 #include "string-util.h"
Brad Bishop19323692019-04-05 15:28:33 -0400413 #include "tmpfile-util.h"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800414+#include "parse-printf-format.h"
415
416 #define SNDBUF_SIZE (8*1024*1024)
417