@@ -159,19 +159,6 @@ nexttok(const char **pos, struct strbuf *buf)
159159 return 0 ;
160160}
161161
162- struct xbps_fmt_conv {
163- enum { HUMANIZE = 1 , STRMODE } type ;
164- union {
165- struct humanize {
166- unsigned width : 8 ;
167- unsigned minscale : 8 ;
168- unsigned maxscale : 8 ;
169- bool decimal : 1 ;
170- int flags ;
171- } humanize ;
172- };
173- };
174-
175162static int
176163parse_u (const char * * pos , unsigned int * u )
177164{
@@ -188,6 +175,129 @@ parse_u(const char **pos, unsigned int *u)
188175 return 0 ;
189176}
190177
178+ static int
179+ parse_d (const char * * pos , int64_t * d )
180+ {
181+ char * e = NULL ;
182+ long v ;
183+ errno = 0 ;
184+ v = strtol (* pos , & e , 10 );
185+ if (errno != 0 )
186+ return - errno ;
187+ if (v > UINT_MAX )
188+ return - ERANGE ;
189+ * d = v ;
190+ * pos = e ;
191+ return 0 ;
192+ }
193+
194+ static int
195+ parse_default (const char * * pos , struct xbps_fmt * fmt , struct strbuf * buf ,
196+ struct xbps_fmt_def * def_storage )
197+ {
198+ struct strbuf buf2 = {0 };
199+ struct xbps_fmt_def * def ;
200+ const char * p = * pos ;
201+ char * str = NULL ;
202+ int r ;
203+
204+ if (* p ++ != '?' )
205+ return 0 ;
206+ if (!def_storage ) {
207+ fmt -> def = def = calloc (1 , sizeof (* def ));
208+ if (!def )
209+ return - errno ;
210+ } else {
211+ fmt -> def = def = def_storage ;
212+ }
213+
214+ if ((* p >= '0' && * p <= '9' ) || * p == '-' ) {
215+ r = parse_d (& p , & def -> val .num );
216+ if (r < 0 )
217+ return r ;
218+ def -> type = XBPS_FMT_DEF_NUM ;
219+ * pos = p ;
220+ return 0 ;
221+ } else if (strncmp (p , "true" , sizeof ("true" ) - 1 ) == 0 ) {
222+ * pos = p + sizeof ("true" ) - 1 ;
223+ def -> type = XBPS_FMT_DEF_BOOL ;
224+ def -> val .boolean = true;
225+ return 0 ;
226+ } else if (strncmp (p , "false" , sizeof ("false" ) - 1 ) == 0 ) {
227+ * pos = p + sizeof ("false" ) - 1 ;
228+ def -> type = XBPS_FMT_DEF_BOOL ;
229+ def -> val .boolean = false;
230+ return 0 ;
231+ }
232+
233+ if (* p ++ != '"' )
234+ return - EINVAL ;
235+
236+ if (!buf ) {
237+ buf = & buf2 ;
238+ } else {
239+ r = strbuf_putc (buf , '\0' );
240+ if (r < 0 )
241+ return r ;
242+ str = buf -> mem + buf -> len ;
243+ }
244+ for (; * p && * p != '"' ; p ++ ) {
245+ switch (* p ) {
246+ case '\\' :
247+ switch (* ++ p ) {
248+ case '\\' : r = strbuf_putc (buf , '\\' ); break ;
249+ case 'a' : r = strbuf_putc (buf , '\a' ); break ;
250+ case 'b' : r = strbuf_putc (buf , '\b' ); break ;
251+ case 'f' : r = strbuf_putc (buf , '\f' ); break ;
252+ case 'n' : r = strbuf_putc (buf , '\n' ); break ;
253+ case 'r' : r = strbuf_putc (buf , '\r' ); break ;
254+ case 't' : r = strbuf_putc (buf , '\t' ); break ;
255+ case '0' : r = strbuf_putc (buf , '\0' ); break ;
256+ case '"' : r = strbuf_putc (buf , '"' ); break ;
257+ default : r = - EINVAL ;
258+ }
259+ break ;
260+ default :
261+ r = strbuf_putc (buf , * p );
262+ }
263+ if (r < 0 )
264+ goto err ;
265+ }
266+ if (* p ++ != '"' ) {
267+ r = - EINVAL ;
268+ goto err ;
269+ }
270+ * pos = p ;
271+ def -> type = XBPS_FMT_DEF_STR ;
272+ if (buf == & buf2 ) {
273+ def -> val .str = strdup (buf2 .mem );
274+ if (!def -> val .str ) {
275+ r = - errno ;
276+ goto err ;
277+ }
278+ strbuf_release (& buf2 );
279+ } else {
280+ def -> val .str = str ;
281+ }
282+ return 0 ;
283+ err :
284+ strbuf_release (& buf2 );
285+ return r ;
286+ }
287+
288+ struct xbps_fmt_conv {
289+ enum { HUMANIZE = 1 , STRMODE } type ;
290+ union {
291+ struct humanize {
292+ unsigned width : 8 ;
293+ unsigned minscale : 8 ;
294+ unsigned maxscale : 8 ;
295+ bool decimal : 1 ;
296+ int flags ;
297+ } humanize ;
298+ };
299+ };
300+
191301static int
192302parse_humanize (const char * * pos , struct humanize * humanize )
193303{
@@ -346,6 +456,7 @@ parse_spec(const char **pos, struct xbps_fmt *fmt, struct xbps_fmt_spec *spec_st
346456static int
347457parse (const char * * pos , struct xbps_fmt * fmt ,
348458 struct strbuf * buf ,
459+ struct xbps_fmt_def * def_storage ,
349460 struct xbps_fmt_conv * conv_storage ,
350461 struct xbps_fmt_spec * spec_storage )
351462{
@@ -357,7 +468,7 @@ parse(const char **pos, struct xbps_fmt *fmt,
357468 return - EINVAL ;
358469 p ++ ;
359470
360- /* var ::= '{' name [conversion][format_spec] '}' */
471+ /* var ::= '{' name [default][ conversion][format_spec] '}' */
361472
362473 /* name ::= [a-zA-Z0-9_-]+ */
363474 for (e = p ; (* e >= 'a' && * e <= 'z' ) ||
@@ -380,6 +491,11 @@ parse(const char **pos, struct xbps_fmt *fmt,
380491 }
381492 p = e ;
382493
494+ /* default ::= ['?' ...] */
495+ r = parse_default (& p , fmt , buf , def_storage );
496+ if (r < 0 )
497+ return r ;
498+
383499 /* conversion ::= ['!' ...] */
384500 r = parse_conversion (& p , fmt , conv_storage );
385501 if (r < 0 )
@@ -426,7 +542,7 @@ xbps_fmt_parse(const char *format)
426542 t = nexttok (& pos , & buf );
427543 }
428544 if (t == TVAR ) {
429- r = parse (& pos , & fmt [n ], NULL , NULL , NULL );
545+ r = parse (& pos , & fmt [n ], NULL , NULL , NULL , NULL );
430546 if (r < 0 )
431547 goto err ;
432548 }
@@ -453,6 +569,9 @@ xbps_fmt_free(struct xbps_fmt *fmt)
453569 for (struct xbps_fmt * f = fmt ; f -> prefix || f -> var ; f ++ ) {
454570 free (f -> prefix );
455571 free (f -> var );
572+ if (f -> def && f -> def -> type == XBPS_FMT_DEF_STR )
573+ free (f -> def -> val .str );
574+ free (f -> def );
456575 free (f -> spec );
457576 free (f -> conv );
458577 }
@@ -477,10 +596,11 @@ xbps_fmts(const char *format, xbps_fmt_cb *cb, void *data, FILE *fp)
477596 t = nexttok (& pos , & buf );
478597 }
479598 if (t == TVAR ) {
480- struct xbps_fmt_spec spec = {0 };
599+ struct xbps_fmt_def def = {0 };
481600 struct xbps_fmt_conv conv = {0 };
601+ struct xbps_fmt_spec spec = {0 };
482602 struct xbps_fmt fmt = { .var = buf .mem };
483- r = parse (& pos , & fmt , & buf , & conv , & spec );
603+ r = parse (& pos , & fmt , & buf , & def , & conv , & spec );
484604 if (r < 0 )
485605 goto out ;
486606 r = cb (fp , & fmt , data );
@@ -617,7 +737,18 @@ xbps_fmt_print_object(const struct xbps_fmt *fmt, xbps_object_t obj, FILE *fp)
617737 return xbps_fmt_print_string (fmt , xbps_string_cstring_nocopy (obj ),
618738 xbps_string_size (obj ), fp );
619739 case XBPS_TYPE_UNKNOWN :
620- return xbps_fmt_print_string (fmt , "(null)" , 0 , fp );
740+ if (fmt -> def ) {
741+ struct xbps_fmt_def * def = fmt -> def ;
742+ switch (fmt -> def -> type ) {
743+ case XBPS_FMT_DEF_BOOL :
744+ return xbps_fmt_print_string (fmt , def -> val .boolean ?
745+ "true" : "false" , 0 , fp );
746+ case XBPS_FMT_DEF_STR :
747+ return xbps_fmt_print_string (fmt , def -> val .str , 0 , fp );
748+ case XBPS_FMT_DEF_NUM :
749+ return xbps_fmt_print_number (fmt , def -> val .num , fp );
750+ }
751+ }
621752 default :
622753 break ;
623754 }
0 commit comments