chiark / gitweb /
cgroup2: use new fstype for unified hierarchy
[elogind.git] / src / basic / parse-printf-format.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2014 Emil Renner Berthing <systemd@esmil.dk>
5
6   With parts from the musl C library
7   Copyright 2005-2014 Rich Felker, et al.
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <stddef.h>
24 #include <string.h>
25
26 #include "parse-printf-format.h"
27
28 #ifndef HAVE_PRINTF_H
29
30 static const char *consume_nonarg(const char *fmt)
31 {
32         do {
33                 if (*fmt == '\0')
34                         return fmt;
35         } while (*fmt++ != '%');
36         return fmt;
37 }
38
39 static const char *consume_num(const char *fmt)
40 {
41         for (;*fmt >= '0' && *fmt <= '9'; fmt++)
42                 /* do nothing */;
43         return fmt;
44 }
45
46 static const char *consume_argn(const char *fmt, size_t *arg)
47 {
48         const char *p = fmt;
49         size_t val = 0;
50
51         if (*p < '1' || *p > '9')
52                 return fmt;
53         do {
54                 val = 10*val + (*p++ - '0');
55         } while (*p >= '0' && *p <= '9');
56
57         if (*p != '$')
58                 return fmt;
59         *arg = val;
60         return p+1;
61 }
62
63 static const char *consume_flags(const char *fmt)
64 {
65         while (1) {
66                 switch (*fmt) {
67                 case '#':
68                 case '0':
69                 case '-':
70                 case ' ':
71                 case '+':
72                 case '\'':
73                 case 'I':
74                         fmt++;
75                         continue;
76                 }
77                 return fmt;
78         }
79 }
80
81 enum state {
82         BARE,
83         LPRE,
84         LLPRE,
85         HPRE,
86         HHPRE,
87         BIGLPRE,
88         ZTPRE,
89         JPRE,
90         STOP
91 };
92
93 enum type {
94         NONE,
95         PTR,
96         INT,
97         UINT,
98         ULLONG,
99         LONG,
100         ULONG,
101         SHORT,
102         USHORT,
103         CHAR,
104         UCHAR,
105         LLONG,
106         SIZET,
107         IMAX,
108         UMAX,
109         PDIFF,
110         UIPTR,
111         DBL,
112         LDBL,
113         MAXTYPE
114 };
115
116 static const short pa_types[MAXTYPE] = {
117         [NONE]   = PA_INT,
118         [PTR]    = PA_POINTER,
119         [INT]    = PA_INT,
120         [UINT]   = PA_INT,
121         [ULLONG] = PA_INT | PA_FLAG_LONG_LONG,
122         [LONG]   = PA_INT | PA_FLAG_LONG,
123         [ULONG]  = PA_INT | PA_FLAG_LONG,
124         [SHORT]  = PA_INT | PA_FLAG_SHORT,
125         [USHORT] = PA_INT | PA_FLAG_SHORT,
126         [CHAR]   = PA_CHAR,
127         [UCHAR]  = PA_CHAR,
128         [LLONG]  = PA_INT | PA_FLAG_LONG_LONG,
129         [SIZET]  = PA_INT | PA_FLAG_LONG,
130         [IMAX]   = PA_INT | PA_FLAG_LONG_LONG,
131         [UMAX]   = PA_INT | PA_FLAG_LONG_LONG,
132         [PDIFF]  = PA_INT | PA_FLAG_LONG_LONG,
133         [UIPTR]  = PA_INT | PA_FLAG_LONG,
134         [DBL]    = PA_DOUBLE,
135         [LDBL]   = PA_DOUBLE | PA_FLAG_LONG_DOUBLE
136 };
137
138 #define S(x) [(x)-'A']
139 #define E(x) (STOP + (x))
140
141 static const unsigned char states[]['z'-'A'+1] = {
142         { /* 0: bare types */
143                 S('d') = E(INT), S('i') = E(INT),
144                 S('o') = E(UINT),S('u') = E(UINT),S('x') = E(UINT), S('X') = E(UINT),
145                 S('e') = E(DBL), S('f') = E(DBL), S('g') = E(DBL),  S('a') = E(DBL),
146                 S('E') = E(DBL), S('F') = E(DBL), S('G') = E(DBL),  S('A') = E(DBL),
147                 S('c') = E(CHAR),S('C') = E(INT),
148                 S('s') = E(PTR), S('S') = E(PTR), S('p') = E(UIPTR),S('n') = E(PTR),
149                 S('m') = E(NONE),
150                 S('l') = LPRE,   S('h') = HPRE, S('L') = BIGLPRE,
151                 S('z') = ZTPRE,  S('j') = JPRE, S('t') = ZTPRE
152         }, { /* 1: l-prefixed */
153                 S('d') = E(LONG), S('i') = E(LONG),
154                 S('o') = E(ULONG),S('u') = E(ULONG),S('x') = E(ULONG),S('X') = E(ULONG),
155                 S('e') = E(DBL),  S('f') = E(DBL),  S('g') = E(DBL),  S('a') = E(DBL),
156                 S('E') = E(DBL),  S('F') = E(DBL),  S('G') = E(DBL),  S('A') = E(DBL),
157                 S('c') = E(INT),  S('s') = E(PTR),  S('n') = E(PTR),
158                 S('l') = LLPRE
159         }, { /* 2: ll-prefixed */
160                 S('d') = E(LLONG), S('i') = E(LLONG),
161                 S('o') = E(ULLONG),S('u') = E(ULLONG),
162                 S('x') = E(ULLONG),S('X') = E(ULLONG),
163                 S('n') = E(PTR)
164         }, { /* 3: h-prefixed */
165                 S('d') = E(SHORT), S('i') = E(SHORT),
166                 S('o') = E(USHORT),S('u') = E(USHORT),
167                 S('x') = E(USHORT),S('X') = E(USHORT),
168                 S('n') = E(PTR),
169                 S('h') = HHPRE
170         }, { /* 4: hh-prefixed */
171                 S('d') = E(CHAR), S('i') = E(CHAR),
172                 S('o') = E(UCHAR),S('u') = E(UCHAR),
173                 S('x') = E(UCHAR),S('X') = E(UCHAR),
174                 S('n') = E(PTR)
175         }, { /* 5: L-prefixed */
176                 S('e') = E(LDBL),S('f') = E(LDBL),S('g') = E(LDBL), S('a') = E(LDBL),
177                 S('E') = E(LDBL),S('F') = E(LDBL),S('G') = E(LDBL), S('A') = E(LDBL),
178                 S('n') = E(PTR)
179         }, { /* 6: z- or t-prefixed (assumed to be same size) */
180                 S('d') = E(PDIFF),S('i') = E(PDIFF),
181                 S('o') = E(SIZET),S('u') = E(SIZET),
182                 S('x') = E(SIZET),S('X') = E(SIZET),
183                 S('n') = E(PTR)
184         }, { /* 7: j-prefixed */
185                 S('d') = E(IMAX), S('i') = E(IMAX),
186                 S('o') = E(UMAX), S('u') = E(UMAX),
187                 S('x') = E(UMAX), S('X') = E(UMAX),
188                 S('n') = E(PTR)
189         }
190 };
191
192 size_t parse_printf_format(const char *fmt, size_t n, int *types)
193 {
194         size_t i = 0;
195         size_t last = 0;
196
197         memset(types, 0, n);
198
199         while (1) {
200                 size_t arg;
201                 unsigned int state;
202
203                 fmt = consume_nonarg(fmt);
204                 if (*fmt == '\0')
205                         break;
206                 if (*fmt == '%') {
207                         fmt++;
208                         continue;
209                 }
210                 arg = 0;
211                 fmt = consume_argn(fmt, &arg);
212                 /* flags */
213                 fmt = consume_flags(fmt);
214                 /* width */
215                 if (*fmt == '*') {
216                         size_t warg = 0;
217                         fmt = consume_argn(fmt+1, &warg);
218                         if (warg == 0)
219                                 warg = ++i;
220                         if (warg > last)
221                                 last = warg;
222                         if (warg <= n && types[warg-1] == NONE)
223                                 types[warg-1] = INT;
224                 } else
225                         fmt = consume_num(fmt);
226                 /* precision */
227                 if (*fmt == '.') {
228                         fmt++;
229                         if (*fmt == '*') {
230                                 size_t parg = 0;
231                                 fmt = consume_argn(fmt+1, &parg);
232                                 if (parg == 0)
233                                         parg = ++i;
234                                 if (parg > last)
235                                         last = parg;
236                                 if (parg <= n && types[parg-1] == NONE)
237                                         types[parg-1] = INT;
238                         } else {
239                                 if (*fmt == '-')
240                                         fmt++;
241                                 fmt = consume_num(fmt);
242                         }
243                 }
244                 /* length modifier and conversion specifier */
245                 state = BARE;
246                 do {
247                         unsigned char c = *fmt++;
248
249                         if (c < 'A' || c > 'z')
250                                 continue;
251                         state = states[state]S(c);
252                         if (state == 0)
253                                 continue;
254                 } while (state < STOP);
255
256                 if (state == E(NONE))
257                         continue;
258
259                 if (arg == 0)
260                         arg = ++i;
261                 if (arg > last)
262                         last = arg;
263                 if (arg <= n)
264                         types[arg-1] = state - STOP;
265         }
266
267         if (last > n)
268                 last = n;
269         for (i = 0; i < last; i++)
270                 types[i] = pa_types[types[i]];
271
272         return last;
273 }
274
275 #endif // HAVE_PRINTF_H