| From 6f9454184a02310802b1ed3e40287958b524a495 Mon Sep 17 00:00:00 2001 |
| From: Tim Orling <timothy.t.orling@linux.intel.com> |
| Date: Thu, 28 Dec 2017 21:39:51 -0800 |
| Subject: [PATCH 2/3] musl does not provide printf.h |
| |
| Reuse the approach from systemd: |
| systemd/0001-add-fallback-parse_printf_format-implementation.patch |
| |
| Original patch author: Emil Renner Berthing <systemd@esmil.dk> |
| Includes work by: Khem Raj <raj.khem@gmail.com> |
| |
| Signed-off-by: Tim Orling <timothy.t.orling@linux.intel.com> |
| --- |
| Upstream-Status: Pending |
| |
| Makefile.am | 4 + |
| configure.ac | 3 + |
| src/log.c | 1 + |
| src/parse-printf-format.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++ |
| src/parse-printf-format.h | 57 ++++++++++ |
| src/stdio-util.h | 1 - |
| 6 files changed, 338 insertions(+), 1 deletion(-) |
| create mode 100644 src/parse-printf-format.c |
| create mode 100644 src/parse-printf-format.h |
| |
| diff --git a/Makefile.am b/Makefile.am |
| index 9bbc8fa..b887d16 100644 |
| --- a/Makefile.am |
| +++ b/Makefile.am |
| @@ -169,6 +169,10 @@ libutils_la_SOURCES = \ |
| src/util.c \ |
| src/util.h |
| |
| +if !HAVE_PRINTF_H |
| +libutils_la_SOURCES += src/parse-printf-format.c |
| +endif |
| + |
| libutils_la_CFLAGS = \ |
| $(AM_CFLAGS) \ |
| $(LIBSYSTEMD_CFLAGS) |
| diff --git a/configure.ac b/configure.ac |
| index 7f74bac..062e310 100644 |
| --- a/configure.ac |
| +++ b/configure.ac |
| @@ -73,6 +73,9 @@ AS_IF([test "x$with_libsystemd" != xno], |
| )] |
| ) |
| |
| +AC_CHECK_HEADERS([printf.h], [], []) |
| +AM_CONDITIONAL(HAVE_PRINTF_H, [test "x$ac_cv_header_print_h" = xyes]) |
| + |
| CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ |
| -pipe \ |
| -Wall \ |
| diff --git a/src/log.c b/src/log.c |
| index 15dec83..aecf231 100644 |
| --- a/src/log.c |
| +++ b/src/log.c |
| @@ -28,6 +28,7 @@ |
| #include <sys/uio.h> |
| #include <unistd.h> |
| |
| +#include "parse-printf-format.h" |
| #include "sd-messages.h" |
| |
| #include "fd-util.h" |
| diff --git a/src/parse-printf-format.c b/src/parse-printf-format.c |
| new file mode 100644 |
| index 0000000..49437e5 |
| --- /dev/null |
| +++ b/src/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/parse-printf-format.h b/src/parse-printf-format.h |
| new file mode 100644 |
| index 0000000..4371177 |
| --- /dev/null |
| +++ b/src/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" |
| + |
| +#ifdef 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/stdio-util.h b/src/stdio-util.h |
| index 0a67557..21cc515 100644 |
| --- a/src/stdio-util.h |
| +++ b/src/stdio-util.h |
| @@ -19,7 +19,6 @@ |
| along with systemd; If not, see <http://www.gnu.org/licenses/>. |
| ***/ |
| |
| -#include <printf.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <sys/types.h> |
| -- |
| 2.13.6 |
| |