{"id":125,"date":"2020-11-29T23:53:50","date_gmt":"2020-11-29T23:53:50","guid":{"rendered":"https:\/\/www.aya.io\/ayablog\/?p=125"},"modified":"2022-02-07T18:57:59","modified_gmt":"2022-02-07T18:57:59","slug":"hackathon-cpp-haiku","status":"publish","type":"post","link":"https:\/\/www.aya.io\/blog\/hackathon-cpp-haiku\/","title":{"rendered":"Hackathon C++ dans Haiku"},"content":{"rendered":"<p>Juste pour le fun j'ai voulu porter un exercice en C++ sur <a href=\"https:\/\/www.haiku-os.org\">Haiku<\/a>, le syst\u00e8me d'exploitation alternatif qui imite l'aspect de <a href=\"https:\/\/fr.wikipedia.org\/wiki\/BeOS\">BeOS<\/a> et en reprend les API syst\u00e8me, mais dont le coeur est bas\u00e9 sur Linux.<\/p>\n<p><!-- more --><\/p>\n<p>Pas de r\u00e9dactionnel d\u00e9taill\u00e9 malheureusement, car je n'avais pas pr\u00e9vu d'en faire un article de blog au d\u00e9but, mais je vous montre un peu quand m\u00eame.<\/p>\n<p>Je n'ai pas eu trop de surprises quant \u00e0 l'installation de Haiku dans VirtualBox d'abord, puis VMWare Fusion Core (bien plus rapide et tout aussi gratuit). <\/p>\n<p>Haiku est un super OS tr\u00e8s l\u00e9ger, fluide, agr\u00e9able \u00e0 utiliser, mais encore tr\u00e8s limit\u00e9 en applications disponibles. Tout d\u00e9marre instanan\u00e9ment, le syst\u00e8me lui-m\u00eame comme les apps, le build de notre app est imm\u00e9diat, l'UI est hyper r\u00e9active, etc. Dans une VM avec juste 1GB de RAM et un seul core processeur d\u00e9di\u00e9. Joli !<\/p>\n<p>J'ai utilis\u00e9 Paladin, un des \u00e9diteurs de code disponibles dans la distribution. Minimaliste, c'esr le moins qu'on puisse dire. Mais \u00e7a \u00e9dite et \u00e7a build, donc on s'en sort pas si mal. Sinon y'avait Vim pas loin...<\/p>\n<p>La difficult\u00e9 principale a \u00e9t\u00e9 que je n'ai pas r\u00e9ussi \u00e0 installer les biblioth\u00e8ques <code>boost<\/code> ni m\u00eame \u00e0 simplement compiler <code>libcurl<\/code> pour Haiku, donc pour la partie REST-client j'ai fini par faire des appels \u00e0 <code>curl<\/code> comme un goret, mais bon, allez, je me pardonne.<\/p>\n<p>Au final un beau moment de nostalgie - ah la la c'\u00e9tait vraiment bien BeOS, et Haiku reprend le flambeau avec moultes promesses - et une belle aventure au pays des syst\u00e8mes alternatifs.<\/p>\n<blockquote>\n<p>Config PLD pour Paladin:<\/p>\n<\/blockquote>\n<pre><code class=\"language-txt\">NAME=WeatherManHaiku\nTARGETNAME=WeatherManHaiku\nPLATFORM=HaikuGCC4\nSCM=git\nGROUP=Source files\nEXPANDGROUP=yes\nSOURCEFILE=CURLDownloader.cpp\nSOURCEFILE=CURLDownloader.hpp\nSOURCEFILE=URLResult.hpp\nSOURCEFILE=Utils.cpp\nSOURCEFILE=Utils.hpp\nSOURCEFILE=Weather.cpp\nSOURCEFILE=Weather.hpp\nSOURCEFILE=main.cpp\nLOCALINCLUDE=.\nSYSTEMINCLUDE=B_FIND_PATH_DEVELOP_HEADERS_DIRECTORY\/be\nSYSTEMINCLUDE=B_FIND_PATH_DEVELOP_HEADERS_DIRECTORY\/cpp\nSYSTEMINCLUDE=B_FIND_PATH_DEVELOP_HEADERS_DIRECTORY\/posix\nLIBRARY=B_FIND_PATH_DEVELOP_LIB_DIRECTORY\/libbe.so\nRUNARGS=\nCCDEBUG=no\nCCPROFILE=no\nCCOPSIZE=no\nCCOPLEVEL=0\nCCTARGETTYPE=0\nCCEXTRA=\nLDEXTRA=<\/code><\/pre>\n<blockquote>\n<p>main.cpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#include &quot;URLResult.hpp&quot;\n#include &quot;CURLDownloader.hpp&quot;\n#include &quot;Utils.hpp&quot;\n#include &quot;Weather.hpp&quot;\n\nint main(int argc, const char * argv[])\n{\n    CURLDownloader dl;\n    URLResult result = dl.makeURL(argc, argv);  \n    if (result.success) {\n        clear_screen();\n        print(&quot;Downloading data...&quot;);\n        std::string json_string = dl.download(result.url);\n        Weather w = dl.parse(json_string);\n        clear_screen();\n        print(w.description());\n        exit(0);\n    } else {\n        print(&quot;\\nOops, that didn&#039;t work out very well...&quot;);  \n        exit(1);\n    }\n}<\/code><\/pre>\n<blockquote>\n<p>Weather.hpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#ifndef Weather_hpp\n#define Weather_hpp\n\n#include &lt;iostream&gt;\n#include &lt;cmath&gt;\n#include &lt;vector&gt;\n#include &lt;ctime&gt;\n#include &lt;iomanip&gt;\n#include &quot;Utils.hpp&quot;\n\nstruct DateTime {\n    std::string date;\n    std::string time;\n};\n\nclass Weather {\npublic:\n    float temp;\n    std::string city;\n    std::string country;\n    std::string category;\n    std::string sub_category;\n    float wind_speed;\n    float wind_direction;\n    float wind_speed_kmh();\n    std::string wind_direction_compass();\n    std::string description();\nprivate:\n    DateTime date_formatted();\n};\n\n#endif \/* Weather_hpp *\/<\/code><\/pre>\n<blockquote>\n<p>Weather.cpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#include &quot;Weather.hpp&quot;\n\nfloat Weather::wind_speed_kmh()\n{\n    return floor(((wind_speed * 3.6) * 5 + 0.5) \/ 5);\n}\n\nstd::string Weather::wind_direction_compass()\n{\n    std::vector&lt;std::string&gt; compass = {&quot;Nord&quot;,&quot;Nord Nord-Est&quot;,&quot;Nord-Est&quot;,&quot;Est-Nord-Est&quot;,&quot;Est&quot;,&quot;Est-Sud-Est&quot;,&quot;Sud-Est&quot;,&quot;Sud-Sud-Est&quot;,&quot;Sud&quot;,&quot;Sud-Sud-Ouest&quot;,&quot;Sud-Ouest&quot;,&quot;Ouest-Sud-Ouest&quot;,&quot;Ouest&quot;,&quot;Ouest-Nord-Ouest&quot;,&quot;Nord-Ouest&quot;,&quot;Nord-Nord-Ouest&quot;};\n    float wd = (wind_direction \/ 22.5) + 0.5;\n    \/\/ % (modulo operator) is not available for floats, use fmod\n    int index = fmod(wd, 16);\n    return compass[index];\n}\n\nstd::string Weather::description()\n{\n    \/\/ DateTime is a struct defined in the header\n    DateTime dt = date_formatted();\n    std::string dts = dt.date + &quot;, &quot; + dt.time;\n    std::string cel = float_to_string(temp, 1);\n    std::string ci = city + &quot; (&quot; + country + &quot;), le &quot; + dts + &quot;.\\n&quot;;\n    std::string te = &quot;Temp\u00e9rature: &quot; + cel + &quot;\u00b0C.\\n&quot;;\n    std::string ca = ci + te + &quot;Temps: &quot; + category + &quot;.\\n&quot;;\n    \/\/ TODO: check if wind exists in API response before using it\n    std::string w = float_to_string(wind_speed_kmh(), 1);\n    std::string desc = ca + &quot;Vent: &quot; + wind_direction_compass() + &quot; \u00e0 &quot; + w + &quot; km\/h.\\n&quot;;\n    return desc;\n}\n\nDateTime Weather::date_formatted()\n{\n    time_t temps;\n    struct tm datetime;\n    char format_date[32];\n    char format_temps[32];\n    time(&amp;temps);\n    datetime = *localtime(&amp;temps);\n    strftime(format_date, 32, &quot;%d\/%m\/%Y&quot;, &amp;datetime);\n    strftime(format_temps, 32, &quot;%Hh%M&quot;, &amp;datetime);\n    DateTime dt;\n    dt.date = (std::string) format_date;\n    dt.time = (std::string) format_temps;\n    return dt;\n}<\/code><\/pre>\n<blockquote>\n<p>Utils.hpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#ifndef Utils_hpp\n#define Utils_hpp\n\n#include &lt;iostream&gt;\n#include &lt;iomanip&gt;\n#include &lt;cstdio&gt;\n#include &lt;stdexcept&gt;\n#include &lt;string&gt;\n#include &lt;array&gt;\n\nvoid clear_screen();\nstd::string exec(const char* cmd);\nstd::string float_to_string(float const&amp; f, int const&amp; p);\nvoid print(std::string const&amp; s);\n\n#endif \/* Utils_hpp *\/<\/code><\/pre>\n<blockquote>\n<p>Utils.cpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#include &quot;Utils.hpp&quot;\n\nvoid clear_screen()\n{\n    std::string cs = &quot;clear&quot;;\n    const char *p = cs.c_str();\n    auto clear = exec(p);\n    print(clear);\n}\n\nstd::string float_to_string(float const&amp; f, int const&amp; p)\n{\n    std::stringstream stream;\n    stream &lt;&lt; std::fixed &lt;&lt; std::setprecision(p) &lt;&lt; f;\n    return stream.str();\n}\n\nvoid print(std::string const&amp; s)\n{\n    std::cout &lt;&lt; s &lt;&lt; std::endl;\n}\n\nstd::string exec(const char* cmd) {\n    std::array&lt;char, 128&gt; buffer;\n    std::string result;\n    std::unique_ptr&lt;FILE, decltype(&amp;pclose)&gt; pipe(popen(cmd, &quot;r&quot;), pclose);\n    if (!pipe) {\n        throw std::runtime_error(&quot;popen() failed!&quot;);\n    }\n    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {\n        result += buffer.data();\n    }\n    return result;\n}<\/code><\/pre>\n<blockquote>\n<p>URLResult.hpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#ifndef URLResult_hpp\n#define URLResult_hpp\n\n#include &lt;string&gt;\n\nstruct URLResult {\n    URLResult(bool s, std::string r) : success(s), url(r) {};\n    bool success;\n    std::string url;\n};\n\n#endif \/* URLResult_hpp *\/<\/code><\/pre>\n<blockquote>\n<p>CURLDownloader.hpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#ifndef CURLDOWNLOADER_HPP\n#define CURLDOWNLOADER_HPP\n\n#include &quot;URLResult.hpp&quot;\n#include &quot;Utils.hpp&quot;\n#include &quot;Weather.hpp&quot;\n#include &quot;rapidjson\/document.h&quot;\n\nclass CURLDownloader {\npublic:\n    Weather parse(const std::string&amp; json_string);\n    std::string download(const std::string&amp; url);\n    URLResult makeURL(int argc, const char * argv[]);\n};\n\n#endif  \/* CURLDOWNLOADER_HPP *\/<\/code><\/pre>\n<blockquote>\n<p>CURLDownloader.cpp<\/p>\n<\/blockquote>\n<pre><code class=\"language-cpp\">#include &quot;CURLDownloader.hpp&quot;\n\nusing namespace rapidjson;\n\nWeather CURLDownloader::parse(const std::string&amp; json_string)\n{\n        Document document;\n        const char *json_chars = json_string.c_str();\n        document.Parse(json_chars);\n        auto main = document[&quot;main&quot;].GetObject();\n        auto temp = main[&quot;temp&quot;].GetFloat();\n        auto city = document[&quot;name&quot;].GetString();\n        auto sys = document[&quot;sys&quot;].GetObject();\n        auto country = sys[&quot;country&quot;].GetString();\n        auto wind = document[&quot;wind&quot;].GetObject();\n        auto wind_speed = wind[&quot;speed&quot;].GetFloat();\n        auto wind_direction = wind[&quot;deg&quot;].GetFloat();\n        auto it = document[&quot;weather&quot;].GetArray();\n        auto first = it[0].GetObject();\n        auto cat = first[&quot;description&quot;].GetString();\n        Weather w;\n        w.temp = temp;\n        w.city = city;\n        w.country = country;\n        w.wind_speed = wind_speed;\n        w.wind_direction = wind_direction;\n        w.category = cat;\n        return w;\n}\n\nURLResult CURLDownloader::makeURL(int argc, const char * argv[])\n{\n    if(argc &gt; 1)\n    {\n        \/\/ make a single string from all CLI input\n        std::string input;\n        for(int i = 1; i &lt; argc; i++) {\n            input += argv[i];\n        }\n\n        std::string url = &quot;http:\/\/api.openweathermap.org\/data\/2.5\/weather?q=&quot;\n        + input\n        + &quot;&amp;appid=d21991d7851f849bfe8cc24d12c795d0&amp;units=metric&amp;lang=fr&quot;;\n\n        return URLResult(true, url);\n    }\n    return URLResult(false, &quot;&quot;);\n}\n\nstd::string CURLDownloader::download(const std::string &amp;url)\n{\n    std::string result;\n    std::string cmd = &quot;curl -s \\&quot;&quot; + url + &quot;\\&quot;&quot;;\n    const char *cstr = cmd.c_str();\n    result = exec(cstr);\n    return result;\n}<\/code><\/pre>\n<h2>Instructions<\/h2>\n<p>Si Paladin est bien param\u00e9tr\u00e9 vous cliquez simplement sur <code>build<\/code>.<\/p>\n<p>Sinon, <code>cd<\/code> dans le dossier qui contient les fichiers, puis <code>g++<\/code> tout le monde. <\/p>\n<p>Il se peut que vous ayez \u00e0 installer des biblioth\u00e8ques manquantes \u00e0 partir du gestionnaire de paquets.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Juste pour le fun j&rsquo;ai voulu porter un exercice en C++ sur Haiku, le syst\u00e8me d&rsquo;exploitation alternatif qui imite l&rsquo;aspect de BeOS et en reprend les API syst\u00e8me, mais dont le coeur est bas\u00e9 sur Linux. Pas de r\u00e9dactionnel d\u00e9taill\u00e9 malheureusement, car je n&rsquo;avais pas pr\u00e9vu d&rsquo;en faire un article de blog au d\u00e9but, mais&hellip; <a class=\"more-link\" href=\"https:\/\/www.aya.io\/blog\/hackathon-cpp-haiku\/\">Poursuivre la lecture <span class=\"screen-reader-text\">Hackathon C++ dans Haiku<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":213,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,5,27,15,16],"tags":[],"class_list":["post-125","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c","category-dev","category-haiku","category-linux","category-os","entry"],"_links":{"self":[{"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/posts\/125","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/comments?post=125"}],"version-history":[{"count":11,"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/posts\/125\/revisions"}],"predecessor-version":[{"id":215,"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/posts\/125\/revisions\/215"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/media\/213"}],"wp:attachment":[{"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/media?parent=125"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/categories?post=125"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aya.io\/blog\/wp-json\/wp\/v2\/tags?post=125"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}