@@ -227,13 +227,76 @@ parse_u(const char **pos, unsigned int *u)
227227}
228228
229229static int
230- parse (const char * * pos , struct strbuf * buf , struct xbps_fmt_spec * spec , struct conversion * conversion )
230+ parse_humanize (const char * * pos , struct humanize * humanize )
231231{
232+ const char * scale = "BKMGTPE" ;
232233 const char * p = * pos ;
233- const char * e ;
234- int r ;
234+ const char * p1 ;
235+
236+ /* default: !humanize .8Ki:8 */
237+ humanize -> width = 8 ;
238+ humanize -> minscale = 2 ;
239+ humanize -> flags = HN_DECIMAL |HN_IEC_PREFIXES ;
240+ humanize -> flags = HN_NOSPACE ;
241+
242+ /* humanize[ ][.][i][width][minscale[maxscale]] */
243+
244+ if (* p == ' ' ) {
245+ humanize -> flags &= ~HN_NOSPACE ;
246+ p ++ ;
247+ }
248+ if (* p == '.' ) {
249+ humanize -> flags |= HN_DECIMAL ;
250+ p ++ ;
251+ }
252+ if ((* p >= '0' && * p <= '9' )) {
253+ unsigned width = 0 ;
254+ int r = parse_u (& p , & width );
255+ if (r < 0 )
256+ return r ;
257+ humanize -> width = width <= 12 ? width : 12 ;
258+ }
259+ if ((p1 = strchr (scale , * p ))) {
260+ humanize -> minscale = p1 - scale + 1 ;
261+ p ++ ;
262+ if ((p1 = strchr (scale , * p ))) {
263+ humanize -> maxscale = p1 - scale + 1 ;
264+ p ++ ;
265+ }
266+ }
267+ if (* p == 'i' ) {
268+ humanize -> flags |= HN_IEC_PREFIXES ;
269+ p ++ ;
270+ }
271+ * pos = p ;
272+ return 0 ;
273+ }
274+
275+ static int
276+ parse_conversion (const char * * pos , struct conversion * conversion )
277+ {
278+ if (* * pos != '!' )
279+ return 0 ;
280+ if (strncmp (* pos + 1 , "strmode" , sizeof ("strmode" ) - 1 ) == 0 ) {
281+ * pos += sizeof ("strmode" );
282+ conversion -> type = STRMODE ;
283+ return 0 ;
284+ } else if (strncmp (* pos + 1 , "humanize" , sizeof ("humanize" ) - 1 ) == 0 ) {
285+ conversion -> type = HUMANIZE ;
286+ * pos += sizeof ("humanize" );
287+ return parse_humanize (pos , & conversion -> humanize );
288+ }
289+ return - EINVAL ;
290+ }
291+
292+ static int
293+ parse_spec (const char * * pos , struct xbps_fmt_spec * spec )
294+ {
235295 bool fill = false;
296+ const char * p = * pos ;
297+ int r ;
236298
299+ /* defaults */
237300 spec -> conversion = NULL ;
238301 spec -> fill = ' ' ;
239302 spec -> align = '>' ;
@@ -242,12 +305,85 @@ parse(const char **pos, struct strbuf *buf, struct xbps_fmt_spec *spec, struct c
242305 spec -> precision = 0 ;
243306 spec -> type = '\0' ;
244307
308+ /* format_spec ::= [[fill]align][sign][zero][width][.precision][type] */
309+
310+ if (* p != ':' )
311+ return 0 ;
312+ p ++ ;
313+
314+ /* fill ::= . */
315+ if (* p && strchr ("<>=" , p [1 ])) {
316+ fill = true;
317+ spec -> fill = * p ;
318+ spec -> align = p [1 ];
319+ p += 2 ;
320+ }
321+
322+ /* align ::= [<>=] */
323+ if (strchr ("<>=" , * p )) {
324+ spec -> align = * p ;
325+ p += 1 ;
326+ }
327+
328+ /* sign ::= [+-] */
329+ if (strchr ("+- " , * p )) {
330+ spec -> sign = * p ;
331+ p += 1 ;
332+ }
333+
334+ /* zero ::= [0] */
335+ if (* p == '0' ) {
336+ if (!fill ) {
337+ spec -> fill = '0' ;
338+ spec -> align = '=' ;
339+ }
340+ p ++ ;
341+ }
342+
343+ /* width ::= [[0-9]+] */
344+ if ((* p >= '0' && * p <= '9' )) {
345+ r = parse_u (& p , & spec -> width );
346+ if (r < 0 )
347+ return r ;
348+ }
349+
350+ /* precision ::= ['.' [0-9]+] */
351+ if (* p == '.' ) {
352+ p ++ ;
353+ r = parse_u (& p , & spec -> precision );
354+ if (r < 0 )
355+ return r ;
356+ }
357+
358+ /* type ::= [[a-zA-Z]] */
359+ if ((* p >= 'a' && * p <= 'z' ) ||
360+ (* p >= 'A' && * p <= 'Z' ))
361+ spec -> type = * p ++ ;
362+
363+ * pos = p ;
364+ return 0 ;
365+ }
366+
367+ static int
368+ parse (const char * * pos , struct strbuf * buf , struct xbps_fmt_spec * spec , struct conversion * conversion )
369+ {
370+ const char * p = * pos ;
371+ const char * e ;
372+ int r ;
373+
245374 if (* p != '{' )
246375 return - EINVAL ;
247376 p ++ ;
248377
249- e = strpbrk (p , "!:}" );
250- if (!e )
378+ /* var ::= '{' name [conversion][format_spec] '}' */
379+
380+ /* name ::= [a-zA-Z0-9_-]+ */
381+ for (e = p ; (* e >= 'a' && * e <= 'z' ) ||
382+ (* e >= 'A' && * e <= 'Z' ) ||
383+ (* e >= '0' && * e <= '0' ) ||
384+ (* e == '_' || * e == '-' ); e ++ )
385+ ;
386+ if (e == p )
251387 return - EINVAL ;
252388
253389 strbuf_reset (buf );
@@ -256,92 +392,16 @@ parse(const char **pos, struct strbuf *buf, struct xbps_fmt_spec *spec, struct c
256392 return r ;
257393 p = e ;
258394
259- if (* p == '!' ) {
260- if (strncmp (p + 1 , "humanize" , sizeof ("humanize" ) - 1 ) == 0 ) {
261- /* humanize[ ][.][i][width][minscale[maxscale]] */
262- const char * scale = "BKMGTPE" ;
263- const char * p1 ;
264- p += sizeof ("humanize" );
265- conversion -> type = HUMANIZE ;
266- if (* p != ':' && * p != '}' ) {
267- conversion -> humanize .flags = HN_NOSPACE ;
268- if (* p == ' ' ) {
269- conversion -> humanize .flags &= ~HN_NOSPACE ;
270- p ++ ;
271- }
272- if (* p == '.' ) {
273- conversion -> humanize .flags |= HN_DECIMAL ;
274- p ++ ;
275- }
276- if ((* p >= '0' && * p <= '9' )) {
277- unsigned width = 0 ;
278- r = parse_u (& p , & width );
279- if (r < 0 )
280- return r ;
281- conversion -> humanize .width = width <= 12 ? width : 12 ;
282- }
283- if ((p1 = strchr (scale , * p ))) {
284- conversion -> humanize .minscale = p1 - scale + 1 ;
285- p ++ ;
286- if ((p1 = strchr (scale , * p ))) {
287- conversion -> humanize .maxscale = p1 - scale + 1 ;
288- p ++ ;
289- }
290- }
291- if (* p == 'i' ) {
292- conversion -> humanize .flags |= HN_IEC_PREFIXES ;
293- p ++ ;
294- }
295- } else {
296- /* default: !humanize .8Ki:8 */
297- conversion -> humanize .width = 8 ;
298- conversion -> humanize .minscale = 2 ;
299- conversion -> humanize .flags = HN_DECIMAL |HN_IEC_PREFIXES ;
300- }
301- } else if (strncmp (p + 1 , "strmode" , sizeof ("strmode" ) - 1 ) == 0 ) {
302- p += sizeof ("strmode" );
303- conversion -> type = STRMODE ;
304- } else {
305- return - EINVAL ;
306- }
307- }
395+ /* conversion ::= ['!' ...] */
396+ r = parse_conversion (& p , conversion );
397+ if (r < 0 )
398+ return r ;
399+
400+ /* format_spec ::= [':' ...] */
401+ r = parse_spec (& p , spec );
402+ if (r < 0 )
403+ return r ;
308404
309- if (* p == ':' ) {
310- p ++ ;
311- if (* p && strchr ("<>=" , p [1 ])) {
312- fill = true;
313- spec -> fill = * p ;
314- spec -> align = p [1 ];
315- p += 2 ;
316- } else if (strchr ("<>=" , * p )) {
317- spec -> align = * p ;
318- p += 1 ;
319- }
320- if (strchr ("+- " , * p )) {
321- spec -> sign = * p ;
322- p += 1 ;
323- }
324- if ((* p >= '0' && * p <= '9' )) {
325- if (* p == '0' ) {
326- if (!fill ) {
327- spec -> fill = '0' ;
328- spec -> align = '=' ;
329- }
330- p ++ ;
331- }
332- r = parse_u (& p , & spec -> width );
333- if (r < 0 )
334- return r ;
335- }
336- if (* p == '.' ) {
337- p ++ ;
338- r = parse_u (& p , & spec -> precision );
339- if (r < 0 )
340- return r ;
341- }
342- if (* p != '}' )
343- spec -> type = * p ++ ;
344- }
345405 if (* p != '}' )
346406 return - EINVAL ;
347407 * pos = p + 1 ;
0 commit comments