77#include < matplot/util/common.h>
88#include < matplot/util/popen.h>
99#include < iostream>
10- #include < regex >
10+ #include < charconv >
1111#include < thread>
1212#include < cstring>
1313#include < cstdlib>
@@ -317,13 +317,28 @@ namespace matplot::backend {
317317 }
318318 }
319319
320+ // / returns the next word in text after prefix terminated with white space.
321+ 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+
320336 std::string gnuplot::default_terminal_type () {
321337 static std::string terminal_type;
322338 const bool dont_know_term_type = terminal_type.empty ();
323339 if (dont_know_term_type) {
324340 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 " );
327342 const bool still_dont_know_term_type = terminal_type.empty ();
328343 if (still_dont_know_term_type) {
329344 terminal_type = " qt" ;
@@ -334,51 +349,25 @@ namespace matplot::backend {
334349
335350 bool gnuplot::terminal_is_available (std::string_view term) {
336351 std::string msg = run_and_get_output (" gnuplot -e \" set terminal " +
337- std::string ( term. data ()) + " \" 2>&1" );
352+ std::string{ term} + " \" 2>&1" );
338353 return msg.empty ();
339354 }
340355
341- 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 });
356+ Version gnuplot::gnuplot_version () {
357+ static auto version = Version{0 , 0 , 0 };
358+ if (!version) {
359+ const auto version_str = run_and_get_output (" gnuplot --version 2>&1" );
360+ const auto major = word_after (version_str, " gnuplot" );
361+ const auto minor = word_after (major, " ." );
362+ const auto patch = word_after (version_str, " patchlevel" );
363+ if (!major.empty () && !minor.empty () && !patch.empty ()) {
364+ std::from_chars (major.begin (), major.end (), version.major );
365+ std::from_chars (minor.begin (), minor.end (), version.minor );
366+ std::from_chars (patch.begin (), patch.end (), version.patch );
380367 }
381368 }
369+ if (!version)
370+ version = {5 , 2 , 6 }; // assume by convention
382371 return version;
383372 }
384373
0 commit comments