417 lines
13 KiB
Diff
417 lines
13 KiB
Diff
|
From 93a4b034c58490d73a7eaae26d262b7de3d19ef6 Mon Sep 17 00:00:00 2001
|
||
|
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
|
||
|
Date: Sun, 18 Aug 2024 02:32:31 -0500
|
||
|
Subject: [PATCH 07/34] Handle lack of <printf.h>
|
||
|
Content-Type: text/plain; charset="utf-8"
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
We are more portable about it than most other patchsets, and we
|
||
|
conditionalise it well enough, but I doubt upstream will accept this.
|
||
|
|
||
|
Signed-off-by: Alexander Miroshnichenko <alex@millerson.name>
|
||
|
---
|
||
|
meson.build | 1 +
|
||
|
src/basic/meson.build | 5 +
|
||
|
src/basic/parse-printf-format.c | 273 ++++++++++++++++++++++++++++++++
|
||
|
src/basic/parse-printf-format.h | 57 +++++++
|
||
|
src/basic/stdio-util.h | 6 +-
|
||
|
5 files changed, 341 insertions(+), 1 deletion(-)
|
||
|
create mode 100644 src/basic/parse-printf-format.c
|
||
|
create mode 100644 src/basic/parse-printf-format.h
|
||
|
|
||
|
diff --git a/meson.build b/meson.build
|
||
|
index c068acc169a3..b11f73dc0c20 100644
|
||
|
--- a/meson.build
|
||
|
+++ b/meson.build
|
||
|
@@ -800,6 +800,7 @@ foreach header : ['crypt.h',
|
||
|
'linux/memfd.h',
|
||
|
'linux/time_types.h',
|
||
|
'linux/vm_sockets.h',
|
||
|
+ 'printf.h',
|
||
|
'sys/auxv.h',
|
||
|
'sys/sdt.h',
|
||
|
'threads.h',
|
||
|
diff --git a/src/basic/meson.build b/src/basic/meson.build
|
||
|
index b538775576ab..ed5ce81876bc 100644
|
||
|
--- a/src/basic/meson.build
|
||
|
+++ b/src/basic/meson.build
|
||
|
@@ -189,6 +189,11 @@ endforeach
|
||
|
|
||
|
basic_sources += generated_gperf_headers
|
||
|
|
||
|
+if conf.get('HAVE_PRINTF_H') != 1
|
||
|
+ basic_sources += [files('parse-printf-format.c')]
|
||
|
+endif
|
||
|
+
|
||
|
+
|
||
|
############################################################
|
||
|
|
||
|
arch_list = [
|
||
|
diff --git a/src/basic/parse-printf-format.c b/src/basic/parse-printf-format.c
|
||
|
new file mode 100644
|
||
|
index 000000000000..49437e544540
|
||
|
--- /dev/null
|
||
|
+++ b/src/basic/parse-printf-format.c
|
||
|
@@ -0,0 +1,273 @@
|
||
|
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||
|
+
|
||
|
+/***
|
||
|
+ This file is part of systemd.
|
||
|
+
|
||
|
+ Copyright 2014 Emil Renner Berthing <systemd@esmil.dk>
|
||
|
+
|
||
|
+ With parts from the musl C library
|
||
|
+ Copyright 2005-2014 Rich Felker, et al.
|
||
|
+
|
||
|
+ systemd is free software; you can redistribute it and/or modify it
|
||
|
+ under the terms of the GNU Lesser General Public License as published by
|
||
|
+ the Free Software Foundation; either version 2.1 of the License, or
|
||
|
+ (at your option) any later version.
|
||
|
+
|
||
|
+ systemd is distributed in the hope that it will be useful, but
|
||
|
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ Lesser General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU Lesser General Public License
|
||
|
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||
|
+***/
|
||
|
+
|
||
|
+#include <stddef.h>
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+#include "parse-printf-format.h"
|
||
|
+
|
||
|
+static const char *consume_nonarg(const char *fmt)
|
||
|
+{
|
||
|
+ do {
|
||
|
+ if (*fmt == '\0')
|
||
|
+ return fmt;
|
||
|
+ } while (*fmt++ != '%');
|
||
|
+ return fmt;
|
||
|
+}
|
||
|
+
|
||
|
+static const char *consume_num(const char *fmt)
|
||
|
+{
|
||
|
+ for (;*fmt >= '0' && *fmt <= '9'; fmt++)
|
||
|
+ /* do nothing */;
|
||
|
+ return fmt;
|
||
|
+}
|
||
|
+
|
||
|
+static const char *consume_argn(const char *fmt, size_t *arg)
|
||
|
+{
|
||
|
+ const char *p = fmt;
|
||
|
+ size_t val = 0;
|
||
|
+
|
||
|
+ if (*p < '1' || *p > '9')
|
||
|
+ return fmt;
|
||
|
+ do {
|
||
|
+ val = 10*val + (*p++ - '0');
|
||
|
+ } while (*p >= '0' && *p <= '9');
|
||
|
+
|
||
|
+ if (*p != '$')
|
||
|
+ return fmt;
|
||
|
+ *arg = val;
|
||
|
+ return p+1;
|
||
|
+}
|
||
|
+
|
||
|
+static const char *consume_flags(const char *fmt)
|
||
|
+{
|
||
|
+ while (1) {
|
||
|
+ switch (*fmt) {
|
||
|
+ case '#':
|
||
|
+ case '0':
|
||
|
+ case '-':
|
||
|
+ case ' ':
|
||
|
+ case '+':
|
||
|
+ case '\'':
|
||
|
+ case 'I':
|
||
|
+ fmt++;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ return fmt;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+enum state {
|
||
|
+ BARE,
|
||
|
+ LPRE,
|
||
|
+ LLPRE,
|
||
|
+ HPRE,
|
||
|
+ HHPRE,
|
||
|
+ BIGLPRE,
|
||
|
+ ZTPRE,
|
||
|
+ JPRE,
|
||
|
+ STOP
|
||
|
+};
|
||
|
+
|
||
|
+enum type {
|
||
|
+ NONE,
|
||
|
+ PTR,
|
||
|
+ INT,
|
||
|
+ UINT,
|
||
|
+ ULLONG,
|
||
|
+ LONG,
|
||
|
+ ULONG,
|
||
|
+ SHORT,
|
||
|
+ USHORT,
|
||
|
+ CHAR,
|
||
|
+ UCHAR,
|
||
|
+ LLONG,
|
||
|
+ SIZET,
|
||
|
+ IMAX,
|
||
|
+ UMAX,
|
||
|
+ PDIFF,
|
||
|
+ UIPTR,
|
||
|
+ DBL,
|
||
|
+ LDBL,
|
||
|
+ MAXTYPE
|
||
|
+};
|
||
|
+
|
||
|
+static const short pa_types[MAXTYPE] = {
|
||
|
+ [NONE] = PA_INT,
|
||
|
+ [PTR] = PA_POINTER,
|
||
|
+ [INT] = PA_INT,
|
||
|
+ [UINT] = PA_INT,
|
||
|
+ [ULLONG] = PA_INT | PA_FLAG_LONG_LONG,
|
||
|
+ [LONG] = PA_INT | PA_FLAG_LONG,
|
||
|
+ [ULONG] = PA_INT | PA_FLAG_LONG,
|
||
|
+ [SHORT] = PA_INT | PA_FLAG_SHORT,
|
||
|
+ [USHORT] = PA_INT | PA_FLAG_SHORT,
|
||
|
+ [CHAR] = PA_CHAR,
|
||
|
+ [UCHAR] = PA_CHAR,
|
||
|
+ [LLONG] = PA_INT | PA_FLAG_LONG_LONG,
|
||
|
+ [SIZET] = PA_INT | PA_FLAG_LONG,
|
||
|
+ [IMAX] = PA_INT | PA_FLAG_LONG_LONG,
|
||
|
+ [UMAX] = PA_INT | PA_FLAG_LONG_LONG,
|
||
|
+ [PDIFF] = PA_INT | PA_FLAG_LONG_LONG,
|
||
|
+ [UIPTR] = PA_INT | PA_FLAG_LONG,
|
||
|
+ [DBL] = PA_DOUBLE,
|
||
|
+ [LDBL] = PA_DOUBLE | PA_FLAG_LONG_DOUBLE
|
||
|
+};
|
||
|
+
|
||
|
+#define S(x) [(x)-'A']
|
||
|
+#define E(x) (STOP + (x))
|
||
|
+
|
||
|
+static const unsigned char states[]['z'-'A'+1] = {
|
||
|
+ { /* 0: bare types */
|
||
|
+ S('d') = E(INT), S('i') = E(INT),
|
||
|
+ S('o') = E(UINT),S('u') = E(UINT),S('x') = E(UINT), S('X') = E(UINT),
|
||
|
+ S('e') = E(DBL), S('f') = E(DBL), S('g') = E(DBL), S('a') = E(DBL),
|
||
|
+ S('E') = E(DBL), S('F') = E(DBL), S('G') = E(DBL), S('A') = E(DBL),
|
||
|
+ S('c') = E(CHAR),S('C') = E(INT),
|
||
|
+ S('s') = E(PTR), S('S') = E(PTR), S('p') = E(UIPTR),S('n') = E(PTR),
|
||
|
+ S('m') = E(NONE),
|
||
|
+ S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
|
||
|
+ S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE
|
||
|
+ }, { /* 1: l-prefixed */
|
||
|
+ S('d') = E(LONG), S('i') = E(LONG),
|
||
|
+ S('o') = E(ULONG),S('u') = E(ULONG),S('x') = E(ULONG),S('X') = E(ULONG),
|
||
|
+ S('e') = E(DBL), S('f') = E(DBL), S('g') = E(DBL), S('a') = E(DBL),
|
||
|
+ S('E') = E(DBL), S('F') = E(DBL), S('G') = E(DBL), S('A') = E(DBL),
|
||
|
+ S('c') = E(INT), S('s') = E(PTR), S('n') = E(PTR),
|
||
|
+ S('l') = LLPRE
|
||
|
+ }, { /* 2: ll-prefixed */
|
||
|
+ S('d') = E(LLONG), S('i') = E(LLONG),
|
||
|
+ S('o') = E(ULLONG),S('u') = E(ULLONG),
|
||
|
+ S('x') = E(ULLONG),S('X') = E(ULLONG),
|
||
|
+ S('n') = E(PTR)
|
||
|
+ }, { /* 3: h-prefixed */
|
||
|
+ S('d') = E(SHORT), S('i') = E(SHORT),
|
||
|
+ S('o') = E(USHORT),S('u') = E(USHORT),
|
||
|
+ S('x') = E(USHORT),S('X') = E(USHORT),
|
||
|
+ S('n') = E(PTR),
|
||
|
+ S('h') = HHPRE
|
||
|
+ }, { /* 4: hh-prefixed */
|
||
|
+ S('d') = E(CHAR), S('i') = E(CHAR),
|
||
|
+ S('o') = E(UCHAR),S('u') = E(UCHAR),
|
||
|
+ S('x') = E(UCHAR),S('X') = E(UCHAR),
|
||
|
+ S('n') = E(PTR)
|
||
|
+ }, { /* 5: L-prefixed */
|
||
|
+ S('e') = E(LDBL),S('f') = E(LDBL),S('g') = E(LDBL), S('a') = E(LDBL),
|
||
|
+ S('E') = E(LDBL),S('F') = E(LDBL),S('G') = E(LDBL), S('A') = E(LDBL),
|
||
|
+ S('n') = E(PTR)
|
||
|
+ }, { /* 6: z- or t-prefixed (assumed to be same size) */
|
||
|
+ S('d') = E(PDIFF),S('i') = E(PDIFF),
|
||
|
+ S('o') = E(SIZET),S('u') = E(SIZET),
|
||
|
+ S('x') = E(SIZET),S('X') = E(SIZET),
|
||
|
+ S('n') = E(PTR)
|
||
|
+ }, { /* 7: j-prefixed */
|
||
|
+ S('d') = E(IMAX), S('i') = E(IMAX),
|
||
|
+ S('o') = E(UMAX), S('u') = E(UMAX),
|
||
|
+ S('x') = E(UMAX), S('X') = E(UMAX),
|
||
|
+ S('n') = E(PTR)
|
||
|
+ }
|
||
|
+};
|
||
|
+
|
||
|
+size_t parse_printf_format(const char *fmt, size_t n, int *types)
|
||
|
+{
|
||
|
+ size_t i = 0;
|
||
|
+ size_t last = 0;
|
||
|
+
|
||
|
+ memset(types, 0, n);
|
||
|
+
|
||
|
+ while (1) {
|
||
|
+ size_t arg;
|
||
|
+ unsigned int state;
|
||
|
+
|
||
|
+ fmt = consume_nonarg(fmt);
|
||
|
+ if (*fmt == '\0')
|
||
|
+ break;
|
||
|
+ if (*fmt == '%') {
|
||
|
+ fmt++;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ arg = 0;
|
||
|
+ fmt = consume_argn(fmt, &arg);
|
||
|
+ /* flags */
|
||
|
+ fmt = consume_flags(fmt);
|
||
|
+ /* width */
|
||
|
+ if (*fmt == '*') {
|
||
|
+ size_t warg = 0;
|
||
|
+ fmt = consume_argn(fmt+1, &warg);
|
||
|
+ if (warg == 0)
|
||
|
+ warg = ++i;
|
||
|
+ if (warg > last)
|
||
|
+ last = warg;
|
||
|
+ if (warg <= n && types[warg-1] == NONE)
|
||
|
+ types[warg-1] = INT;
|
||
|
+ } else
|
||
|
+ fmt = consume_num(fmt);
|
||
|
+ /* precision */
|
||
|
+ if (*fmt == '.') {
|
||
|
+ fmt++;
|
||
|
+ if (*fmt == '*') {
|
||
|
+ size_t parg = 0;
|
||
|
+ fmt = consume_argn(fmt+1, &parg);
|
||
|
+ if (parg == 0)
|
||
|
+ parg = ++i;
|
||
|
+ if (parg > last)
|
||
|
+ last = parg;
|
||
|
+ if (parg <= n && types[parg-1] == NONE)
|
||
|
+ types[parg-1] = INT;
|
||
|
+ } else {
|
||
|
+ if (*fmt == '-')
|
||
|
+ fmt++;
|
||
|
+ fmt = consume_num(fmt);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ /* length modifier and conversion specifier */
|
||
|
+ state = BARE;
|
||
|
+ do {
|
||
|
+ unsigned char c = *fmt++;
|
||
|
+
|
||
|
+ if (c < 'A' || c > 'z')
|
||
|
+ continue;
|
||
|
+ state = states[state]S(c);
|
||
|
+ if (state == 0)
|
||
|
+ continue;
|
||
|
+ } while (state < STOP);
|
||
|
+
|
||
|
+ if (state == E(NONE))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (arg == 0)
|
||
|
+ arg = ++i;
|
||
|
+ if (arg > last)
|
||
|
+ last = arg;
|
||
|
+ if (arg <= n)
|
||
|
+ types[arg-1] = state - STOP;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (last > n)
|
||
|
+ last = n;
|
||
|
+ for (i = 0; i < last; i++)
|
||
|
+ types[i] = pa_types[types[i]];
|
||
|
+
|
||
|
+ return last;
|
||
|
+}
|
||
|
diff --git a/src/basic/parse-printf-format.h b/src/basic/parse-printf-format.h
|
||
|
new file mode 100644
|
||
|
index 000000000000..47be7522d7fa
|
||
|
--- /dev/null
|
||
|
+++ b/src/basic/parse-printf-format.h
|
||
|
@@ -0,0 +1,57 @@
|
||
|
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||
|
+
|
||
|
+/***
|
||
|
+ This file is part of systemd.
|
||
|
+
|
||
|
+ Copyright 2014 Emil Renner Berthing <systemd@esmil.dk>
|
||
|
+
|
||
|
+ With parts from the GNU C Library
|
||
|
+ Copyright 1991-2014 Free Software Foundation, Inc.
|
||
|
+
|
||
|
+ systemd is free software; you can redistribute it and/or modify it
|
||
|
+ under the terms of the GNU Lesser General Public License as published by
|
||
|
+ the Free Software Foundation; either version 2.1 of the License, or
|
||
|
+ (at your option) any later version.
|
||
|
+
|
||
|
+ systemd is distributed in the hope that it will be useful, but
|
||
|
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ Lesser General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU Lesser General Public License
|
||
|
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||
|
+***/
|
||
|
+
|
||
|
+#pragma once
|
||
|
+
|
||
|
+#include "config.h"
|
||
|
+
|
||
|
+#if HAVE_PRINTF_H
|
||
|
+#include <printf.h>
|
||
|
+#else
|
||
|
+
|
||
|
+#include <stddef.h>
|
||
|
+
|
||
|
+enum { /* C type: */
|
||
|
+ PA_INT, /* int */
|
||
|
+ PA_CHAR, /* int, cast to char */
|
||
|
+ PA_WCHAR, /* wide char */
|
||
|
+ PA_STRING, /* const char *, a '\0'-terminated string */
|
||
|
+ PA_WSTRING, /* const wchar_t *, wide character string */
|
||
|
+ PA_POINTER, /* void * */
|
||
|
+ PA_FLOAT, /* float */
|
||
|
+ PA_DOUBLE, /* double */
|
||
|
+ PA_LAST
|
||
|
+};
|
||
|
+
|
||
|
+/* Flag bits that can be set in a type returned by `parse_printf_format'. */
|
||
|
+#define PA_FLAG_MASK 0xff00
|
||
|
+#define PA_FLAG_LONG_LONG (1 << 8)
|
||
|
+#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
|
||
|
+#define PA_FLAG_LONG (1 << 9)
|
||
|
+#define PA_FLAG_SHORT (1 << 10)
|
||
|
+#define PA_FLAG_PTR (1 << 11)
|
||
|
+
|
||
|
+size_t parse_printf_format(const char *fmt, size_t n, int *types);
|
||
|
+
|
||
|
+#endif /* HAVE_PRINTF_H */
|
||
|
diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h
|
||
|
index 0a2239d02259..259255fc651d 100644
|
||
|
--- a/src/basic/stdio-util.h
|
||
|
+++ b/src/basic/stdio-util.h
|
||
|
@@ -1,12 +1,16 @@
|
||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||
|
#pragma once
|
||
|
|
||
|
-#include <printf.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
#include "macro.h"
|
||
|
+#if HAVE_PRINTF_H
|
||
|
+#include <printf.h>
|
||
|
+#else
|
||
|
+#include "parse-printf-format.h"
|
||
|
+#endif
|
||
|
|
||
|
_printf_(3, 4)
|
||
|
static inline char* snprintf_ok(char *buf, size_t len, const char *format, ...) {
|
||
|
--
|
||
|
2.41.0
|
||
|
|