@@ -384,4 +384,153 @@ std::string escape_filename_spaces(const std::string& filename)
384
384
return out;
385
385
}
386
386
387
+ void format_emit_unescaped (std::string &result, std::string_view fmt)
388
+ {
389
+ result.reserve (result.size () + fmt.size ());
390
+ for (size_t i = 0 ; i < fmt.size (); ++i) {
391
+ char ch = fmt[i];
392
+ result.push_back (ch);
393
+ if (ch == ' %' && i + 1 < fmt.size () && fmt[i + 1 ] == ' %' ) {
394
+ ++i;
395
+ }
396
+ }
397
+ }
398
+
399
+ std::string unescape_format_string (std::string_view fmt)
400
+ {
401
+ std::string result;
402
+ format_emit_unescaped (result, fmt);
403
+ return result;
404
+ }
405
+
406
+ static std::string string_view_stringf (std::string_view spec, ...)
407
+ {
408
+ std::string fmt (spec);
409
+ char format_specifier = fmt[fmt.size () - 1 ];
410
+ switch (format_specifier) {
411
+ case ' d' :
412
+ case ' i' :
413
+ case ' o' :
414
+ case ' u' :
415
+ case ' x' :
416
+ case ' X' : {
417
+ // Strip any length modifier off `fmt`
418
+ std::string long_fmt;
419
+ for (size_t i = 0 ; i + 1 < fmt.size (); ++i) {
420
+ char ch = fmt[i];
421
+ if ((ch >= ' a' && ch <= ' z' ) || (ch >= ' A' && ch <= ' Z' )) {
422
+ break ;
423
+ }
424
+ long_fmt.push_back (ch);
425
+ }
426
+ // Add `lld` or whatever
427
+ long_fmt += " ll" ;
428
+ long_fmt.push_back (format_specifier);
429
+ fmt = long_fmt;
430
+ break ;
431
+ }
432
+ default :
433
+ break ;
434
+ }
435
+
436
+ va_list ap;
437
+ va_start (ap, spec);
438
+ std::string result = vstringf (fmt.c_str (), ap);
439
+ va_end (ap);
440
+ return result;
441
+ }
442
+
443
+ template <typename Arg>
444
+ static void format_emit_stringf (std::string &result, std::string_view spec, int *dynamic_ints,
445
+ DynamicIntCount num_dynamic_ints, Arg arg)
446
+ {
447
+ // Delegate nontrivial formats to the C library.
448
+ switch (num_dynamic_ints) {
449
+ case DynamicIntCount::NONE:
450
+ result += string_view_stringf (spec, arg);
451
+ return ;
452
+ case DynamicIntCount::ONE:
453
+ result += string_view_stringf (spec, dynamic_ints[0 ], arg);
454
+ return ;
455
+ case DynamicIntCount::TWO:
456
+ result += string_view_stringf (spec, dynamic_ints[0 ], dynamic_ints[1 ], arg);
457
+ return ;
458
+ }
459
+ YOSYS_ABORT (" Internal error" );
460
+ }
461
+
462
+ void format_emit_long_long (std::string &result, std::string_view spec, int *dynamic_ints,
463
+ DynamicIntCount num_dynamic_ints, long long arg)
464
+ {
465
+ if (spec == " %d" ) {
466
+ // Format checking will have guaranteed num_dynamic_ints == 0.
467
+ result += std::to_string (arg);
468
+ return ;
469
+ }
470
+ format_emit_stringf (result, spec, dynamic_ints, num_dynamic_ints, arg);
471
+ }
472
+
473
+ void format_emit_unsigned_long_long (std::string &result, std::string_view spec, int *dynamic_ints,
474
+ DynamicIntCount num_dynamic_ints, unsigned long long arg)
475
+ {
476
+ if (spec == " %u" ) {
477
+ // Format checking will have guaranteed num_dynamic_ints == 0.
478
+ result += std::to_string (arg);
479
+ return ;
480
+ }
481
+ if (spec == " %c" ) {
482
+ result += static_cast <char >(arg);
483
+ return ;
484
+ }
485
+ format_emit_stringf (result, spec, dynamic_ints, num_dynamic_ints, arg);
486
+ }
487
+
488
+ void format_emit_double (std::string &result, std::string_view spec, int *dynamic_ints,
489
+ DynamicIntCount num_dynamic_ints, double arg)
490
+ {
491
+ format_emit_stringf (result, spec, dynamic_ints, num_dynamic_ints, arg);
492
+ }
493
+
494
+ void format_emit_char_ptr (std::string &result, std::string_view spec, int *dynamic_ints,
495
+ DynamicIntCount num_dynamic_ints, const char *arg)
496
+ {
497
+ if (spec == " %s" ) {
498
+ // Format checking will have guaranteed num_dynamic_ints == 0.
499
+ result += arg;
500
+ return ;
501
+ }
502
+ format_emit_stringf (result, spec, dynamic_ints, num_dynamic_ints, arg);
503
+ }
504
+
505
+ void format_emit_string (std::string &result, std::string_view spec, int *dynamic_ints,
506
+ DynamicIntCount num_dynamic_ints, const std::string &arg)
507
+ {
508
+ if (spec == " %s" ) {
509
+ // Format checking will have guaranteed num_dynamic_ints == 0.
510
+ result += arg;
511
+ return ;
512
+ }
513
+ format_emit_stringf (result, spec, dynamic_ints, num_dynamic_ints, arg.c_str ());
514
+ }
515
+
516
+ void format_emit_string_view (std::string &result, std::string_view spec, int *dynamic_ints,
517
+ DynamicIntCount num_dynamic_ints, std::string_view arg)
518
+ {
519
+ if (spec == " %s" ) {
520
+ // Format checking will have guaranteed num_dynamic_ints == 0.
521
+ // We can output the string without creating a temporary copy.
522
+ result += arg;
523
+ return ;
524
+ }
525
+ // Delegate nontrivial formats to the C library. We need to construct
526
+ // a temporary string to ensure null termination.
527
+ format_emit_stringf (result, spec, dynamic_ints, num_dynamic_ints, std::string (arg).c_str ());
528
+ }
529
+
530
+ void format_emit_void_ptr (std::string &result, std::string_view spec, int *dynamic_ints,
531
+ DynamicIntCount num_dynamic_ints, const void *arg)
532
+ {
533
+ format_emit_stringf (result, spec, dynamic_ints, num_dynamic_ints, arg);
534
+ }
535
+
387
536
YOSYS_NAMESPACE_END
0 commit comments