7
7
#include < matplot/util/common.h>
8
8
#include < matplot/util/popen.h>
9
9
#include < iostream>
10
- #include < regex >
10
+ #include < charconv >
11
11
#include < thread>
12
12
#include < cstring>
13
13
#include < cstdlib>
@@ -317,13 +317,28 @@ namespace matplot::backend {
317
317
}
318
318
}
319
319
320
+ // / returns the next word in text after prefix terminated with white space.
321
+ static std::string_view word_after (std::string_view text, std::string_view prefix)
322
+ {
323
+ auto res = text.substr (0 ,0 );
324
+ if (auto b = text.find (prefix); b != std::string_view::npos) {
325
+ b += prefix.length ();
326
+ while (b < text.length () && std::isspace (text[b]))
327
+ ++b; // skip white space before word
328
+ auto e = b;
329
+ while (e < text.length () && !std::isspace (text[e]))
330
+ ++e; // scan until white space or end
331
+ res = text.substr (b, e-b);
332
+ }
333
+ return res;
334
+ }
335
+
320
336
std::string gnuplot::default_terminal_type () {
321
337
static std::string terminal_type;
322
338
const bool dont_know_term_type = terminal_type.empty ();
323
339
if (dont_know_term_type) {
324
340
terminal_type = run_and_get_output (" gnuplot -e \" show terminal\" 2>&1" );
325
- terminal_type = std::regex_replace (terminal_type,
326
- std::regex (" [^]*terminal type is ([^ ]+)[^]*" ), " $1" );
341
+ terminal_type = word_after (terminal_type, " terminal type is " );
327
342
const bool still_dont_know_term_type = terminal_type.empty ();
328
343
if (still_dont_know_term_type) {
329
344
terminal_type = " qt" ;
@@ -334,54 +349,45 @@ namespace matplot::backend {
334
349
335
350
bool gnuplot::terminal_is_available (std::string_view term) {
336
351
std::string msg = run_and_get_output (" gnuplot -e \" set terminal " +
337
- std::string ( term. data ()) + " \" 2>&1" );
352
+ std::string{ term} + " \" 2>&1" );
338
353
return msg.empty ();
339
354
}
340
355
356
+ template <typename T>
357
+ void convert_to (std::string_view text, T& value) {
358
+ std::from_chars (text.data (), text.data () + text.length (), value);
359
+ }
360
+
341
361
std::tuple<int , int , int > gnuplot::gnuplot_version () {
342
- static std::tuple<int , int , int > version{0 , 0 , 0 };
343
- const bool dont_know_gnuplot_version_yet =
344
- version == std::tuple<int , int , int >({0 , 0 , 0 });
345
- if (dont_know_gnuplot_version_yet) {
346
- std::string version_str =
347
- run_and_get_output (" gnuplot --version 2>&1" );
348
- std::string version_major = std::regex_replace (
349
- version_str,
350
- std::regex (" [^]*gnuplot (\\ d+)\\ .\\ d+ patchlevel \\ d+ *" ),
351
- " $1" );
352
- std::string version_minor = std::regex_replace (
353
- version_str,
354
- std::regex (" [^]*gnuplot \\ d+\\ .(\\ d+) patchlevel \\ d+ *" ),
355
- " $1" );
356
- std::string version_patch = std::regex_replace (
357
- version_str,
358
- std::regex (" [^]*gnuplot \\ d+\\ .\\ d+ patchlevel (\\ d+) *" ),
359
- " $1" );
360
- try {
361
- std::get<0 >(version) = std::stoi (version_major);
362
- } catch (...) {
363
- std::get<0 >(version) = 0 ;
364
- }
365
- try {
366
- std::get<1 >(version) = std::stoi (version_minor);
367
- } catch (...) {
368
- std::get<1 >(version) = 0 ;
369
- }
370
- try {
371
- std::get<2 >(version) = std::stoi (version_patch);
372
- } catch (...) {
373
- std::get<2 >(version) = 0 ;
374
- }
375
- const bool still_dont_know_gnuplot_version =
376
- version == std::tuple<int , int , int >({0 , 0 , 0 });
377
- if (still_dont_know_gnuplot_version) {
378
- // assume it's 5.2.6 by convention
379
- version = std::tuple<int , int , int >({5 , 2 , 6 });
362
+ constexpr auto version_zero = std::make_tuple (0 , 0 , 0 );
363
+ static auto version = version_zero;
364
+ if (version == version_zero) { // unknown version
365
+ const auto version_str = run_and_get_output (" gnuplot --version 2>&1" );
366
+ // gnuplot version_str example: "5.2 patchlevel 6"
367
+ const auto major_minor = word_after (version_str, " gnuplot" ); // "5.2"
368
+ const auto minor = word_after (major_minor, " ." ); // "2"
369
+ const auto patch = word_after (version_str, " patchlevel" ); // "6"
370
+ if (!major_minor.empty () && !minor.empty () && !patch.empty ()) {
371
+ convert_to (major_minor, std::get<0 >(version));
372
+ convert_to (minor, std::get<1 >(version));
373
+ convert_to (patch, std::get<2 >(version));
380
374
}
375
+ if (version == version_zero) // still unknown
376
+ version = {5 , 2 , 6 }; // assume by convention
381
377
}
382
378
return version;
383
379
}
384
380
381
+ bool gnuplot::gnuplot_includes_legends () {
382
+ return gnuplot_version () >= std::make_tuple (5 , 2 , 6 );
383
+ }
384
+ bool gnuplot::gnuplot_has_wall_option () {
385
+ return gnuplot_version () >= std::make_tuple (5 , 5 , 0 );
386
+ }
387
+ bool gnuplot::gnuplot_supports_keyentry () {
388
+ return gnuplot_version () >= std::make_tuple (5 , 2 , 6 );
389
+ }
390
+
385
391
bool gnuplot::terminal_has_title_option (const std::string &t) {
386
392
SV_CONSTEXPR std::string_view whitelist[] = {
387
393
" qt" , " aqua" , " caca" , " canvas" , " windows" , " wxt" , " x11" };
0 commit comments