From 7d8e6cc34f5a1d101b392981a135b499d3b66119 Mon Sep 17 00:00:00 2001 From: "raveit65 (via Travis CI)" Date: Thu, 10 Dec 2020 20:06:18 +0000 Subject: Deploy mate-desktop/libmateweather to github.com/mate-desktop/libmateweather.git:gh-pages --- .../index.html | 131 + .../report-22c0d3.html | 2030 +++++++++++ .../report-565580.html | 917 +++++ .../report-57bf16.html | 433 +++ .../report-7ad762.html | 705 ++++ .../report-7f5d92.html | 917 +++++ .../report-9ce8c7.html | 2030 +++++++++++ .../report-a72fed.html | 925 +++++ .../report-ae2c61.html | 705 ++++ .../report-d460a4.html | 557 +++ .../report-dd38d1.html | 705 ++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-0741a9.html | 917 +++++ .../report-4651e5.html | 925 +++++ .../report-4d810c.html | 917 +++++ .../report-5208f2.html | 705 ++++ .../report-73b580.html | 557 +++ .../report-9da9a1.html | 433 +++ .../report-b7bfc9.html | 2030 +++++++++++ .../report-d0e42f.html | 2030 +++++++++++ .../report-dac547.html | 705 ++++ .../report-e230d5.html | 705 ++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-182943.html | 705 ++++ .../report-312812.html | 557 +++ .../report-3be078.html | 917 +++++ .../report-5f6e58.html | 917 +++++ .../report-65d8b5.html | 705 ++++ .../report-8750f3.html | 2030 +++++++++++ .../report-956099.html | 433 +++ .../report-b1c4ca.html | 925 +++++ .../report-beabf5.html | 705 ++++ .../report-ce9da0.html | 2030 +++++++++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-0641c1.html | 705 ++++ .../report-080384.html | 2030 +++++++++++ .../report-4d7425.html | 705 ++++ .../report-7a46d1.html | 557 +++ .../report-b5419b.html | 925 +++++ .../report-da081d.html | 2030 +++++++++++ .../report-db8db4.html | 917 +++++ .../report-dcd483.html | 917 +++++ .../report-f0b2f9.html | 433 +++ .../report-f724ea.html | 705 ++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-068c2c.html | 2030 +++++++++++ .../report-0a2710.html | 925 +++++ .../report-0c8436.html | 705 ++++ .../report-11da39.html | 557 +++ .../report-2466b3.html | 917 +++++ .../report-7166da.html | 433 +++ .../report-a207c9.html | 705 ++++ .../report-a561e5.html | 917 +++++ .../report-b594e8.html | 705 ++++ .../report-c25aa2.html | 2030 +++++++++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-1298a7.html | 705 ++++ .../report-2c6560.html | 2030 +++++++++++ .../report-7f5301.html | 925 +++++ .../report-8ac26c.html | 705 ++++ .../report-8d2266.html | 557 +++ .../report-94aa15.html | 2030 +++++++++++ .../report-99181e.html | 917 +++++ .../report-aac29d.html | 705 ++++ .../report-b7630e.html | 433 +++ .../report-def332.html | 917 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-09daff.html | 2030 +++++++++++ .../report-18f193.html | 705 ++++ .../report-328456.html | 925 +++++ .../report-3f485d.html | 705 ++++ .../report-4dc92a.html | 557 +++ .../report-57154e.html | 2030 +++++++++++ .../report-74447b.html | 705 ++++ .../report-858b73.html | 917 +++++ .../report-96cada.html | 917 +++++ .../report-daf830.html | 433 +++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-45e2cb.html | 705 ++++ .../report-634d09.html | 917 +++++ .../report-8d0a69.html | 925 +++++ .../report-9c5ce7.html | 705 ++++ .../report-aad064.html | 433 +++ .../report-e78815.html | 2030 +++++++++++ .../report-e9edb2.html | 557 +++ .../report-f0a8d9.html | 917 +++++ .../report-f9ba7d.html | 2030 +++++++++++ .../report-f9eb3e.html | 705 ++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-09d374.html | 705 ++++ .../report-0b3a1f.html | 557 +++ .../report-4297c8.html | 705 ++++ .../report-4793b6.html | 705 ++++ .../report-747b6a.html | 917 +++++ .../report-7ec349.html | 2030 +++++++++++ .../report-8e2595.html | 433 +++ .../report-c73c91.html | 917 +++++ .../report-e26e75.html | 925 +++++ .../report-f1718b.html | 2030 +++++++++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + .../index.html | 131 + .../report-69e3c1.html | 433 +++ .../report-7bac52.html | 2030 +++++++++++ .../report-80b565.html | 925 +++++ .../report-919971.html | 705 ++++ .../report-9d756d.html | 917 +++++ .../report-a57df7.html | 2030 +++++++++++ .../report-b5d653.html | 705 ++++ .../report-cbdc18.html | 705 ++++ .../report-dc17ea.html | 557 +++ .../report-e56eb8.html | 917 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../10.html | 384 +++ .../11.html | 3562 ++++++++++++++++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1122 ++++++ .../7.html | 528 +++ .../8.html | 1324 ++++++++ .../9.html | 876 +++++ .../index.html | 165 + .../stats.html | 119 + .../style.css | 137 + CNAME | 1 + index.html | 46 + 282 files changed, 229167 insertions(+) create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/index.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-22c0d3.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-565580.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-57bf16.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-7ad762.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-7f5d92.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-9ce8c7.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-a72fed.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-ae2c61.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-d460a4.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/report-dd38d1.html create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/scanview.css create mode 100644 2020-11-18-212044-5793-1@b4134f1299e6_master/sorttable.js create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/0.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/1.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/10.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/11.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/2.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/3.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/4.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/5.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/6.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/7.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/8.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/9.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/index.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/stats.html create mode 100644 2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/style.css create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/index.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-0741a9.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4651e5.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4d810c.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-5208f2.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-73b580.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-9da9a1.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-b7bfc9.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-d0e42f.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-dac547.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-e230d5.html create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/scanview.css create mode 100644 2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/sorttable.js create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/0.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/1.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/10.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/11.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/2.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/3.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/4.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/5.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/6.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/7.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/8.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/9.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/index.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/stats.html create mode 100644 2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/style.css create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/index.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-182943.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-312812.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-3be078.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-5f6e58.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-65d8b5.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-8750f3.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-956099.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-b1c4ca.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-beabf5.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/report-ce9da0.html create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/scanview.css create mode 100644 2020-11-20-061953-5797-1@c23ecee40629_master/sorttable.js create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/0.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/1.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/10.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/11.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/2.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/3.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/4.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/5.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/6.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/7.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/8.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/9.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/index.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/stats.html create mode 100644 2020-11-20-062057-5818-cppcheck@c23ecee40629_master/style.css create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/index.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-0641c1.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-080384.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-4d7425.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-7a46d1.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-b5419b.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-da081d.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-db8db4.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-dcd483.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f0b2f9.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f724ea.html create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/scanview.css create mode 100644 2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/sorttable.js create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/0.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/1.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/10.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/11.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/2.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/3.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/4.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/5.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/6.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/7.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/8.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/9.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/index.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/stats.html create mode 100644 2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/style.css create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/index.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-068c2c.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-0a2710.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-0c8436.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-11da39.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-2466b3.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-7166da.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-a207c9.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-a561e5.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-b594e8.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/report-c25aa2.html create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/scanview.css create mode 100644 2020-11-28-203903-5798-1@e376046e52c8_master/sorttable.js create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/0.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/1.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/10.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/11.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/2.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/3.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/4.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/5.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/6.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/7.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/8.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/9.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/index.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/stats.html create mode 100644 2020-11-28-204010-5039-cppcheck@e376046e52c8_master/style.css create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/index.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-1298a7.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-2c6560.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-7f5301.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8ac26c.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8d2266.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-94aa15.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-99181e.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-aac29d.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-b7630e.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/report-def332.html create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/scanview.css create mode 100644 2020-11-28-212732-5799-1@4157215843a8_README-typo/sorttable.js create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/0.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/1.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/10.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/11.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/2.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/3.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/4.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/5.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/6.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/7.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/8.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/9.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/index.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/stats.html create mode 100644 2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/style.css create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/index.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-09daff.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-18f193.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-328456.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-3f485d.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-4dc92a.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-57154e.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-74447b.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-858b73.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-96cada.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-daf830.html create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/scanview.css create mode 100644 2020-12-03-100512-5816-1@888804ba2ee5_fallback/sorttable.js create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/0.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/1.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/10.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/11.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/2.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/3.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/4.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/5.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/6.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/7.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/8.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/9.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/index.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/stats.html create mode 100644 2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/style.css create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/index.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-45e2cb.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-634d09.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-8d0a69.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-9c5ce7.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-aad064.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-e78815.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-e9edb2.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-f0a8d9.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-f9ba7d.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/report-f9eb3e.html create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/scanview.css create mode 100644 2020-12-06-182030-5820-1@03c25106ef43_master/sorttable.js create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/0.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/1.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/10.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/11.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/2.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/3.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/4.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/5.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/6.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/7.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/8.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/9.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/index.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/stats.html create mode 100644 2020-12-06-182137-9773-cppcheck@03c25106ef43_master/style.css create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/index.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-09d374.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-0b3a1f.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-4297c8.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-4793b6.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-747b6a.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-7ec349.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-8e2595.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-c73c91.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-e26e75.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/report-f1718b.html create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/scanview.css create mode 100644 2020-12-08-224639-5819-1@6489fd5efa22_master/sorttable.js create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/0.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/1.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/10.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/11.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/2.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/3.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/4.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/5.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/6.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/7.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/8.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/9.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/index.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/stats.html create mode 100644 2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/style.css create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/index.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-69e3c1.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-7bac52.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-80b565.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-919971.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-9d756d.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-a57df7.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-b5d653.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-cbdc18.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-dc17ea.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-e56eb8.html create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/scanview.css create mode 100644 2020-12-10-200341-5831-1@93dbf10c7ea2_master/sorttable.js create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/0.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/1.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/10.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/11.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/2.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/3.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/4.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/5.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/6.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/7.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/8.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/9.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/index.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/stats.html create mode 100644 2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/style.css create mode 100644 CNAME create mode 100644 index.html diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/index.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/index.html new file mode 100644 index 0000000..4317c07 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@10b65e7a4cb5
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Wed Nov 18 21:20:44 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
+ + diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-22c0d3.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-22c0d3.html new file mode 100644 index 0000000..f147a71 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-22c0d3.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-565580.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-565580.html new file mode 100644 index 0000000..97a4fc7 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-565580.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-57bf16.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-57bf16.html new file mode 100644 index 0000000..2faf409 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-57bf16.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-7ad762.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-7ad762.html new file mode 100644 index 0000000..893e8ba --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-7ad762.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-7f5d92.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-7f5d92.html new file mode 100644 index 0000000..a280285 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-7f5d92.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-9ce8c7.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-9ce8c7.html new file mode 100644 index 0000000..704d4e4 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-9ce8c7.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-a72fed.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-a72fed.html new file mode 100644 index 0000000..994f6e8 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-a72fed.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-ae2c61.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-ae2c61.html new file mode 100644 index 0000000..f6b6925 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-ae2c61.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-d460a4.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-d460a4.html new file mode 100644 index 0000000..dc7ff99 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-d460a4.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/report-dd38d1.html b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-dd38d1.html new file mode 100644 index 0000000..84f8ba8 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/report-dd38d1.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-212044-5793-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/scanview.css b/2020-11-18-212044-5793-1@b4134f1299e6_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-11-18-212044-5793-1@b4134f1299e6_master/sorttable.js b/2020-11-18-212044-5793-1@b4134f1299e6_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-11-18-212044-5793-1@b4134f1299e6_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/1.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/10.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/11.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/2.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/3.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/4.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/5.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/6.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/7.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/8.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/9.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/index.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/stats.html b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/style.css b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-11-18-212150-9974-cppcheck@b4134f1299e6_master/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/index.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/index.html new file mode 100644 index 0000000..b20baf1 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@cb09d6500a65
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Wed Nov 18 22:20:33 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
+ + diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-0741a9.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-0741a9.html new file mode 100644 index 0000000..d42406a --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-0741a9.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4651e5.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4651e5.html new file mode 100644 index 0000000..ba8fd19 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4651e5.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4d810c.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4d810c.html new file mode 100644 index 0000000..2e0721c --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-4d810c.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-5208f2.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-5208f2.html new file mode 100644 index 0000000..b34c9c2 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-5208f2.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-73b580.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-73b580.html new file mode 100644 index 0000000..2575e57 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-73b580.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-9da9a1.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-9da9a1.html new file mode 100644 index 0000000..14ecc90 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-9da9a1.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-b7bfc9.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-b7bfc9.html new file mode 100644 index 0000000..9273b9d --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-b7bfc9.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-d0e42f.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-d0e42f.html new file mode 100644 index 0000000..0075505 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-d0e42f.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-dac547.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-dac547.html new file mode 100644 index 0000000..3b04c2f --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-dac547.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-e230d5.html b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-e230d5.html new file mode 100644 index 0000000..640435b --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/report-e230d5.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-18-222033-5788-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/scanview.css b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/sorttable.js b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-11-18-222033-5788-1@3740d8633e76_USE_MATE2_MACROS/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/1.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/10.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/11.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/2.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/3.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/4.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/5.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/6.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/7.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/8.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/9.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/index.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/stats.html b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/style.css b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-11-18-222143-7798-cppcheck@3740d8633e76_USE_MATE2_MACROS/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/index.html b/2020-11-20-061953-5797-1@c23ecee40629_master/index.html new file mode 100644 index 0000000..cf64054 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@52eb32a8e59b
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Fri Nov 20 06:19:53 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
+ + diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-182943.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-182943.html new file mode 100644 index 0000000..59f8760 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-182943.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-312812.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-312812.html new file mode 100644 index 0000000..37d0494 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-312812.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-3be078.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-3be078.html new file mode 100644 index 0000000..825150c --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-3be078.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-5f6e58.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-5f6e58.html new file mode 100644 index 0000000..08efd3a --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-5f6e58.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-65d8b5.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-65d8b5.html new file mode 100644 index 0000000..0b746b7 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-65d8b5.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-8750f3.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-8750f3.html new file mode 100644 index 0000000..34b5981 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-8750f3.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-956099.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-956099.html new file mode 100644 index 0000000..7d5b2e7 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-956099.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-b1c4ca.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-b1c4ca.html new file mode 100644 index 0000000..efe74eb --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-b1c4ca.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-beabf5.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-beabf5.html new file mode 100644 index 0000000..878c008 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-beabf5.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/report-ce9da0.html b/2020-11-20-061953-5797-1@c23ecee40629_master/report-ce9da0.html new file mode 100644 index 0000000..3c1e0fe --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/report-ce9da0.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-20-061953-5797-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/scanview.css b/2020-11-20-061953-5797-1@c23ecee40629_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-11-20-061953-5797-1@c23ecee40629_master/sorttable.js b/2020-11-20-061953-5797-1@c23ecee40629_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-11-20-061953-5797-1@c23ecee40629_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/1.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/10.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/11.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/2.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/3.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/4.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/5.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/6.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/7.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/8.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/9.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/index.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/stats.html b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/style.css b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-11-20-062057-5818-cppcheck@c23ecee40629_master/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/index.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/index.html new file mode 100644 index 0000000..80a2f4b --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@28722c57917f
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Sat Nov 28 17:13:03 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
+ + diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-0641c1.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-0641c1.html new file mode 100644 index 0000000..91483a1 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-0641c1.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-080384.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-080384.html new file mode 100644 index 0000000..9958562 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-080384.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-4d7425.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-4d7425.html new file mode 100644 index 0000000..c8d8664 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-4d7425.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-7a46d1.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-7a46d1.html new file mode 100644 index 0000000..0b69ddb --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-7a46d1.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-b5419b.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-b5419b.html new file mode 100644 index 0000000..dbe7ddc --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-b5419b.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-da081d.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-da081d.html new file mode 100644 index 0000000..d0ff656 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-da081d.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-db8db4.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-db8db4.html new file mode 100644 index 0000000..30357e0 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-db8db4.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-dcd483.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-dcd483.html new file mode 100644 index 0000000..27d13d3 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-dcd483.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f0b2f9.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f0b2f9.html new file mode 100644 index 0000000..8994ed6 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f0b2f9.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f724ea.html b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f724ea.html new file mode 100644 index 0000000..9b9233f --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/report-f724ea.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-171303-5796-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/scanview.css b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/sorttable.js b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-11-28-171303-5796-1@da459c883ddf_README-i18-LOCATION/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/1.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/10.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/11.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/2.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/3.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/4.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/5.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/6.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/7.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/8.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/9.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/index.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/stats.html b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/style.css b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-11-28-171410-9476-cppcheck@da459c883ddf_README-i18-LOCATION/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/index.html b/2020-11-28-203903-5798-1@e376046e52c8_master/index.html new file mode 100644 index 0000000..b9e1358 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@ee2b8839dddd
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Sat Nov 28 20:39:03 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
+ + diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-068c2c.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-068c2c.html new file mode 100644 index 0000000..c79c517 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-068c2c.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-0a2710.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-0a2710.html new file mode 100644 index 0000000..97d3f09 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-0a2710.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-0c8436.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-0c8436.html new file mode 100644 index 0000000..e8da3c1 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-0c8436.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-11da39.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-11da39.html new file mode 100644 index 0000000..78ba566 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-11da39.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-2466b3.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-2466b3.html new file mode 100644 index 0000000..cd701db --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-2466b3.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-7166da.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-7166da.html new file mode 100644 index 0000000..5e47cfb --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-7166da.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-a207c9.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-a207c9.html new file mode 100644 index 0000000..21af752 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-a207c9.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-a561e5.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-a561e5.html new file mode 100644 index 0000000..060637a --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-a561e5.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-b594e8.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-b594e8.html new file mode 100644 index 0000000..ef71cff --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-b594e8.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/report-c25aa2.html b/2020-11-28-203903-5798-1@e376046e52c8_master/report-c25aa2.html new file mode 100644 index 0000000..ef47de3 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/report-c25aa2.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-203903-5798-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/scanview.css b/2020-11-28-203903-5798-1@e376046e52c8_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-11-28-203903-5798-1@e376046e52c8_master/sorttable.js b/2020-11-28-203903-5798-1@e376046e52c8_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-11-28-203903-5798-1@e376046e52c8_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/1.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/10.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/11.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/2.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/3.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/4.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/5.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/6.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/7.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/8.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/9.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/index.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/stats.html b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/style.css b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-11-28-204010-5039-cppcheck@e376046e52c8_master/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/index.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/index.html new file mode 100644 index 0000000..00f1752 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@92cc109754ad
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Sat Nov 28 21:27:32 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
+ + diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-1298a7.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-1298a7.html new file mode 100644 index 0000000..822c2fc --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-1298a7.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-2c6560.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-2c6560.html new file mode 100644 index 0000000..7cac79a --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-2c6560.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-7f5301.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-7f5301.html new file mode 100644 index 0000000..d67aa9b --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-7f5301.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8ac26c.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8ac26c.html new file mode 100644 index 0000000..0c401d6 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8ac26c.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8d2266.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8d2266.html new file mode 100644 index 0000000..cef73b2 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-8d2266.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-94aa15.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-94aa15.html new file mode 100644 index 0000000..b98e5fa --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-94aa15.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-99181e.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-99181e.html new file mode 100644 index 0000000..711649b --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-99181e.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-aac29d.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-aac29d.html new file mode 100644 index 0000000..c55b1d8 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-aac29d.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-b7630e.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-b7630e.html new file mode 100644 index 0000000..ab850f7 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-b7630e.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-def332.html b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-def332.html new file mode 100644 index 0000000..4dbf0f7 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/report-def332.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-11-28-212732-5799-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/scanview.css b/2020-11-28-212732-5799-1@4157215843a8_README-typo/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-11-28-212732-5799-1@4157215843a8_README-typo/sorttable.js b/2020-11-28-212732-5799-1@4157215843a8_README-typo/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-11-28-212732-5799-1@4157215843a8_README-typo/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/1.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/10.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/11.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/2.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/3.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/4.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/5.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/6.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/7.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/8.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/9.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/index.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/stats.html b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/style.css b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-11-28-212837-7346-cppcheck@4157215843a8_README-typo/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/index.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/index.html new file mode 100644 index 0000000..ff4217c --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@4002f9322f2d
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Thu Dec 3 10:05:12 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
+ + diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-09daff.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-09daff.html new file mode 100644 index 0000000..f06a587 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-09daff.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-18f193.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-18f193.html new file mode 100644 index 0000000..5c1a891 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-18f193.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-328456.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-328456.html new file mode 100644 index 0000000..acf2522 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-328456.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-3f485d.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-3f485d.html new file mode 100644 index 0000000..98f8674 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-3f485d.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-4dc92a.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-4dc92a.html new file mode 100644 index 0000000..b08577f --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-4dc92a.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-57154e.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-57154e.html new file mode 100644 index 0000000..0141428 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-57154e.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-74447b.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-74447b.html new file mode 100644 index 0000000..06678e0 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-74447b.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-858b73.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-858b73.html new file mode 100644 index 0000000..c4812ad --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-858b73.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-96cada.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-96cada.html new file mode 100644 index 0000000..615ee21 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-96cada.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-daf830.html b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-daf830.html new file mode 100644 index 0000000..3651b20 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/report-daf830.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-03-100512-5816-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/scanview.css b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-12-03-100512-5816-1@888804ba2ee5_fallback/sorttable.js b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-12-03-100512-5816-1@888804ba2ee5_fallback/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/1.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/10.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/11.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/2.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/3.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/4.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/5.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/6.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/7.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/8.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/9.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/index.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/stats.html b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/style.css b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-12-03-100620-4062-cppcheck@888804ba2ee5_fallback/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/index.html b/2020-12-06-182030-5820-1@03c25106ef43_master/index.html new file mode 100644 index 0000000..c527852 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@a19b51a6efb9
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Sun Dec 6 18:20:30 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
+ + diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-45e2cb.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-45e2cb.html new file mode 100644 index 0000000..1f2abe6 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-45e2cb.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-634d09.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-634d09.html new file mode 100644 index 0000000..f3421f3 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-634d09.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-8d0a69.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-8d0a69.html new file mode 100644 index 0000000..343d2fe --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-8d0a69.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-9c5ce7.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-9c5ce7.html new file mode 100644 index 0000000..bdd9acf --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-9c5ce7.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-aad064.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-aad064.html new file mode 100644 index 0000000..3ad0cc5 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-aad064.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-e78815.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-e78815.html new file mode 100644 index 0000000..cc88e54 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-e78815.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-e9edb2.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-e9edb2.html new file mode 100644 index 0000000..558274e --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-e9edb2.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-f0a8d9.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-f0a8d9.html new file mode 100644 index 0000000..b73ab5b --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-f0a8d9.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-f9ba7d.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-f9ba7d.html new file mode 100644 index 0000000..f32c439 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-f9ba7d.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/report-f9eb3e.html b/2020-12-06-182030-5820-1@03c25106ef43_master/report-f9eb3e.html new file mode 100644 index 0000000..48c1fc0 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/report-f9eb3e.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-06-182030-5820-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/scanview.css b/2020-12-06-182030-5820-1@03c25106ef43_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-12-06-182030-5820-1@03c25106ef43_master/sorttable.js b/2020-12-06-182030-5820-1@03c25106ef43_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-12-06-182030-5820-1@03c25106ef43_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/1.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/10.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/11.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/2.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/3.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/4.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/5.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/6.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/7.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/8.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/9.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/index.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/stats.html b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/style.css b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-12-06-182137-9773-cppcheck@03c25106ef43_master/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/index.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/index.html new file mode 100644 index 0000000..e25a223 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@0913e1c43b4a
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Tue Dec 8 22:46:39 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
+ + diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-09d374.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-09d374.html new file mode 100644 index 0000000..8f4ab7f --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-09d374.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-0b3a1f.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-0b3a1f.html new file mode 100644 index 0000000..43ac309 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-0b3a1f.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-4297c8.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-4297c8.html new file mode 100644 index 0000000..d2d4d34 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-4297c8.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-4793b6.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-4793b6.html new file mode 100644 index 0000000..b7a037b --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-4793b6.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-747b6a.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-747b6a.html new file mode 100644 index 0000000..de3e7f9 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-747b6a.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-7ec349.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-7ec349.html new file mode 100644 index 0000000..057aca5 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-7ec349.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-8e2595.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-8e2595.html new file mode 100644 index 0000000..0bbdaa3 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-8e2595.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-c73c91.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-c73c91.html new file mode 100644 index 0000000..1fece06 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-c73c91.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-e26e75.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-e26e75.html new file mode 100644 index 0000000..56bf9bb --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-e26e75.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/report-f1718b.html b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-f1718b.html new file mode 100644 index 0000000..e405db8 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/report-f1718b.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-08-224639-5819-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/scanview.css b/2020-12-08-224639-5819-1@6489fd5efa22_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-12-08-224639-5819-1@6489fd5efa22_master/sorttable.js b/2020-12-08-224639-5819-1@6489fd5efa22_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-12-08-224639-5819-1@6489fd5efa22_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/1.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/10.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/11.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/2.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/3.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/4.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/5.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/6.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/7.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/8.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/9.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/index.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/stats.html b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/style.css b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-12-08-224747-8510-cppcheck@6489fd5efa22_master/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/index.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/index.html new file mode 100644 index 0000000..ce88a27 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@af2fd8603b08
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Thu Dec 10 20:03:41 2020
+

Bug Summary

+ + + + + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs10
Dead code
Unreachable code2
Dead store
Dead assignment2
Dead initialization2
Logic error
Dereference of null pointer1
Out-of-bound access1
Security
Potential insecure memory buffer bounds restriction in call 'strcpy'1
Unix Stream API Error
Resource Leak1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentweather.c_weather_info_fill4981View Report
Dead storeDead assignmentweather-metar.cmetar_parse4541View Report
Dead storeDead initializationweather-sun.ccalc_sun21651View Report
Dead storeDead initializationweather-sun.ccalc_sun21641View Report
Logic errorDereference of null pointerweather-met.cmet_reprocess11127View Report
Logic errorOut-of-bound accessweather-metar.cmetar_tok_vis1699View Report
SecurityPotential insecure memory buffer bounds restriction in call 'strcpy'weather.cweather_info_get_update7251View Report
Unix Stream API ErrorResource Leaktest_metar.cmain738View Report
Dead codeUnreachable codeweather-sun.cweather_info_next_sun_event3391View Report
Dead codeUnreachable codeweather-metar.cmetar_tok_vis1771View Report
+ + diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-69e3c1.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-69e3c1.html new file mode 100644 index 0000000..7822852 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-69e3c1.html @@ -0,0 +1,433 @@ + + + +test_metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:test_metar.c
Warning:line 73, column 12
Opened file is never closed; potential resource leak
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name test_metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c test_metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/*
3 * Simple program to reproduce METAR parsing results from command line
4 */
5
6#include <glib.h>
7#include <string.h>
8#include <stdio.h>
9#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
10#include "weather-priv.h"
11
12#ifndef BUFLEN4096
13#define BUFLEN4096 4096
14#endif /* BUFLEN */
15
16int
17main (int argc, char **argv)
18{
19 FILE* stream = stdinstdin;
20 gchar* filename = NULL((void*)0);
21 GOptionEntry entries[] = {
22 { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
23 "file constaining metar observations", NULL((void*)0) },
24 { NULL((void*)0) }
25 };
26 GOptionContext* context;
27 GError* error = NULL((void*)0);
28 char buf[BUFLEN4096];
29 int len;
30 WeatherInfo info;
31
32 context = g_option_context_new ("- test libmateweather metar parser");
33 g_option_context_add_main_entries (context, entries, NULL((void*)0));
34 g_option_context_parse (context, &argc, &argv, &error);
35
36 if (error) {
1
Assuming 'error' is null
2
Taking false branch
37 perror (error->message);
38 return error->code;
39 }
40 if (filename) {
3
Assuming 'filename' is non-null
4
Taking true branch
41 stream = fopen (filename, "r");
42 if (!stream) {
5
Assuming 'stream' is non-null
6
Taking false branch
43 perror ("fopen");
44 return -1;
45 }
46 } else {
47 fprintf (stderrstderr, "Enter a METAR string...\n");
48 }
49
50 while (fgets (buf, sizeof (buf), stream)) {
7
Loop condition is false. Execution continues on line 73
51 len = strlen (buf);
52 if (buf[len - 1] == '\n') {
53 buf[--len] = '\0';
54 }
55 printf ("\n%s\n", buf);
56
57 memset (&info, 0, sizeof (info));
58 info.valid = 1;
59 metar_parse (buf, &info);
60 weather_info_to_metric (&info);
61 printf ("Returned info:\n");
62 printf (" update: %s", ctime (&info.update));
63 printf (" sky: %s\n", weather_info_get_sky (&info));
64 printf (" cond: %s\n", weather_info_get_conditions (&info));
65 printf (" temp: %s\n", weather_info_get_temp (&info));
66 printf (" dewp: %s\n", weather_info_get_dew (&info));
67 printf (" wind: %s\n", weather_info_get_wind (&info));
68 printf (" pressure: %s\n", weather_info_get_pressure (&info));
69 printf (" vis: %s\n", weather_info_get_visibility (&info));
70
71 // TODO: retrieve location's lat/lon to display sunrise/set times
72 }
73 return 0;
8
Opened file is never closed; potential resource leak
74}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-7bac52.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-7bac52.html new file mode 100644 index 0000000..978269a --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-7bac52.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 498, column 9
Value stored to 'location' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
Value stored to 'location' is never read
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-80b565.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-80b565.html new file mode 100644 index 0000000..5009b53 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-80b565.html @@ -0,0 +1,925 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 169, column 24
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
1
Assuming the condition is false
2
Taking false branch
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
3
Assuming the condition is true
4
Taking true branch
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
5
Assuming 'pfrac' is non-null
6
Taking true branch
166 if (*tokp == 'M') {
7
Assuming the condition is false
8
Taking false branch
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
9
Out of bound memory access (access exceeds upper limit of memory block)
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-919971.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-919971.html new file mode 100644 index 0000000..d7e90b0 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-919971.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 165, column 13
Value stored to 'obsLon' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
Value stored to 'obsLon' during its initialization is never read
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-9d756d.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-9d756d.html new file mode 100644 index 0000000..d082f8c --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-9d756d.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 454, column 5
Value stored to 'i' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
Value stored to 'i' is never read
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-a57df7.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-a57df7.html new file mode 100644 index 0000000..62c25c4 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-a57df7.html @@ -0,0 +1,2030 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 725, column 2
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather.c - Overall weather server functions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28#include <math.h>
29#include <fenv.h>
30
31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
34
35#include <time.h>
36#include <unistd.h>
37
38#include <gdk-pixbuf/gdk-pixbuf.h>
39
40#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
41#include "weather.h"
42#include "weather-priv.h"
43
44#define MOON_PHASES36 36
45
46/**
47 * SECTION:weather
48 * @Title: weather
49 */
50
51static void _weather_internal_check (void);
52
53
54static inline void
55mateweather_gettext_init (void)
56{
57 static gsize mateweather_gettext_initialized = FALSE(0);
58
59 if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if (
(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&mateweather_gettext_initialized) : (
(void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(&
mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false"
); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer
*)(&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic
, &gapg_temp_newval, 5); gapg_temp_newval; })) &&
g_once_init_enter (&mateweather_gettext_initialized)); }
))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 0))
) {
60 bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale");
61#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
62 bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8");
63#endif
64 g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&mateweather_gettext_initialized) = ((!(0)))) :
(void) 0; g_once_init_leave ((&mateweather_gettext_initialized
), (gsize) ((!(0)))); }))
;
65 }
66}
67
68const char *
69mateweather_gettext (const char *str)
70{
71 mateweather_gettext_init ();
72 return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5);
73}
74
75const char *
76mateweather_dpgettext (const char *context,
77 const char *str)
78{
79 mateweather_gettext_init ();
80 return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str);
81}
82
83/*
84 * Convert string of the form "DD-MM-SSH" to radians
85 * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
86 * Return value is positive for N,E; negative for S,W.
87 */
88static gdouble
89dmsh2rad (const gchar *latlon)
90{
91 char *p1, *p2;
92 int deg, min, sec, dir;
93 gdouble value;
94
95 if (latlon == NULL((void*)0))
96 return DBL_MAX1.7976931348623157e+308;
97 p1 = strchr (latlon, '-');
98 p2 = strrchr (latlon, '-');
99 if (p1 == NULL((void*)0) || p1 == latlon) {
100 return DBL_MAX1.7976931348623157e+308;
101 } else if (p1 == p2) {
102 sscanf (latlon, "%d-%d", &deg, &min);
103 sec = 0;
104 } else if (p2 == 1 + p1) {
105 return DBL_MAX1.7976931348623157e+308;
106 } else {
107 sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
108 }
109 if (deg > 180 || min >= 60 || sec >= 60)
110 return DBL_MAX1.7976931348623157e+308;
111 value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.;
112
113 dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
114 if (dir == 'W' || dir == 'S')
115 value = -value;
116 else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
117 value = DBL_MAX1.7976931348623157e+308;
118 return value;
119}
120
121WeatherLocation *
122weather_location_new (const gchar *name, const gchar *code,
123 const gchar *zone, const gchar *radar,
124 const gchar *coordinates,
125 const gchar *country_code,
126 const gchar *tz_hint)
127{
128 WeatherLocation *location;
129
130 _weather_internal_check ();
131
132 location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s
== 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n
) && (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
133
134 /* name and metar code must be set */
135 location->name = g_strdup (name);
136 location->code = g_strdup (code);
137
138 if (zone) {
139 location->zone = g_strdup (zone);
140 } else {
141 location->zone = g_strdup ("------");
142 }
143
144 if (radar) {
145 location->radar = g_strdup (radar);
146 } else {
147 location->radar = g_strdup ("---");
148 }
149
150 if (location->zone[0] == '-') {
151 location->zone_valid = FALSE(0);
152 } else {
153 location->zone_valid = TRUE(!(0));
154 }
155
156 location->coordinates = NULL((void*)0);
157 if (coordinates)
158 {
159 char **pieces;
160
161 pieces = g_strsplit (coordinates, " ", -1);
162
163 if (g_strv_length (pieces) == 2)
164 {
165 location->coordinates = g_strdup (coordinates);
166 location->latitude = dmsh2rad (pieces[0]);
167 location->longitude = dmsh2rad (pieces[1]);
168 }
169
170 g_strfreev (pieces);
171 }
172
173 if (!location->coordinates)
174 {
175 location->coordinates = g_strdup ("---");
176 location->latitude = DBL_MAX1.7976931348623157e+308;
177 location->longitude = DBL_MAX1.7976931348623157e+308;
178 }
179
180 location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308);
181
182 location->country_code = g_strdup (country_code);
183 location->tz_hint = g_strdup (tz_hint);
184
185 return location;
186}
187
188WeatherLocation *
189weather_location_clone (const WeatherLocation *location)
190{
191 WeatherLocation *clone;
192
193 g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "location != NULL"
); return (((void*)0)); } } while (0)
;
194
195 clone = weather_location_new (location->name,
196 location->code, location->zone,
197 location->radar, location->coordinates,
198 location->country_code, location->tz_hint);
199 clone->latitude = location->latitude;
200 clone->longitude = location->longitude;
201 clone->latlon_valid = location->latlon_valid;
202 return clone;
203}
204
205void
206weather_location_free (WeatherLocation *location)
207{
208 if (location) {
209 g_free (location->name);
210 g_free (location->code);
211 g_free (location->zone);
212 g_free (location->radar);
213 g_free (location->coordinates);
214 g_free (location->country_code);
215 g_free (location->tz_hint);
216
217 g_free (location);
218 }
219}
220
221gboolean
222weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
223{
224 /* if something is NULL, then it's TRUE if and only if both are NULL) */
225 if (location1 == NULL((void*)0) || location2 == NULL((void*)0))
226 return (location1 == location2);
227 if (!location1->code || !location2->code)
228 return (location1->code == location2->code);
229 if (!location1->name || !location2->name)
230 return (location1->name == location2->name);
231
232 return ((strcmp (location1->code, location2->code) == 0) &&
233 (strcmp (location1->name, location2->name) == 0));
234}
235
236static const gchar *wind_direction_str[] = {
237 N_("Variable")("Variable"),
238 N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"),
239 N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"),
240 N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"),
241 N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest")
242};
243
244const gchar *
245weather_wind_direction_string (WeatherWindDirection wind)
246{
247 if (wind <= WIND_INVALID || wind >= WIND_LAST)
248 return _("Invalid")(mateweather_gettext ("Invalid"));
249
250 return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind]));
251}
252
253static const gchar *sky_str[] = {
254 N_("Clear Sky")("Clear Sky"),
255 N_("Broken clouds")("Broken clouds"),
256 N_("Scattered clouds")("Scattered clouds"),
257 N_("Few clouds")("Few clouds"),
258 N_("Overcast")("Overcast")
259};
260
261const gchar *
262weather_sky_string (WeatherSky sky)
263{
264 if (sky <= SKY_INVALID || sky >= SKY_LAST)
265 return _("Invalid")(mateweather_gettext ("Invalid"));
266
267 return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky]));
268}
269
270
271/*
272 * Even though tedious, I switched to a 2D array for weather condition
273 * strings, in order to facilitate internationalization, esp. for languages
274 * with genders.
275 */
276
277/*
278 * Almost all reportable combinations listed in
279 * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
280 * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
281 * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
282 * Combinations that are not possible are filled in with "??".
283 * Some other exceptions not handled yet, such as "SN BLSN" which has
284 * special meaning.
285 */
286
287/*
288 * Note, magic numbers, when you change the size here, make sure to change
289 * the below function so that new values are recognized
290 */
291/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
292/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
293static const gchar *conditions_str[24][13] = {
294/* Translators: If you want to know what "blowing" "shallow" "partial"
295 * etc means, you can go to http://www.weather.com/glossary/ and
296 * http://www.crh.noaa.gov/arx/wx.tbl.php */
297 /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" },
298 /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") },
299 /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") },
300 /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" },
301 /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
302 /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
303 /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" },
304 /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", },
305 /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" },
306 /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
307 /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
308 /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") },
309 /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
310 /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
311 /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" },
312 /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
313 /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" },
314 /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" },
315 /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
316 /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
317 /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
318 /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
319 /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
320 /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
321};
322
323const gchar *
324weather_conditions_string (WeatherConditions cond)
325{
326 const gchar *str;
327
328 if (!cond.significant) {
329 return "-";
330 } else {
331 if (cond.phenomenon > PHENOMENON_INVALID &&
332 cond.phenomenon < PHENOMENON_LAST &&
333 cond.qualifier > QUALIFIER_INVALID &&
334 cond.qualifier < QUALIFIER_LAST)
335 str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int
)cond.qualifier]))
;
336 else
337 str = _("Invalid")(mateweather_gettext ("Invalid"));
338 return (strlen (str) > 0) ? str : "-";
339 }
340}
341
342/* Locals turned global to facilitate asynchronous HTTP requests */
343
344
345gboolean
346requests_init (WeatherInfo *info)
347{
348 if (info->requests_pending)
349 return FALSE(0);
350
351 return TRUE(!(0));
352}
353
354void request_done (WeatherInfo *info, gboolean ok)
355{
356 if (ok) {
357 (void) calc_sun (info);
358 info->moonValid = info->valid && calc_moon (info);
359 }
360 if (!--info->requests_pending)
361 info->finish_cb (info, info->cb_data);
362}
363
364/* it's OK to pass in NULL */
365void
366free_forecast_list (WeatherInfo *info)
367{
368 GSList *p;
369
370 if (!info)
371 return;
372
373 for (p = info->forecast_list; p; p = p->next)
374 weather_info_free (p->data);
375
376 if (info->forecast_list) {
377 g_slist_free (info->forecast_list);
378 info->forecast_list = NULL((void*)0);
379 }
380}
381
382/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
383
384static inline gdouble
385calc_humidity (gdouble temp, gdouble dewp)
386{
387 gdouble esat, esurf;
388
389 if (temp > -500.0 && dewp > -500.0) {
390 temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0));
391 dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0));
392
393 esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
394 esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
395 } else {
396 esurf = -1.0;
397 esat = 1.0;
398 }
399 return ((esurf/esat) * 100.0);
400}
401
402static inline gdouble
403calc_apparent (WeatherInfo *info)
404{
405 gdouble temp = info->temp;
406 gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779);
407 gdouble apparent = -1000.;
408
409 /*
410 * Wind chill calculations as of 01-Nov-2001
411 * http://www.nws.noaa.gov/om/windchill/index.shtml
412 * Some pages suggest that the formula will soon be adjusted
413 * to account for solar radiation (bright sun vs cloudy sky)
414 */
415 if (temp <= 50.0) {
416 if (wind > 3.0) {
417 gdouble v = pow (wind, 0.16);
418 apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
419 } else if (wind >= 0.) {
420 apparent = temp;
421 }
422 }
423 /*
424 * Heat index calculations:
425 * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
426 */
427 else if (temp >= 80.0) {
428 if (info->temp >= -500. && info->dew >= -500.) {
429 gdouble humidity = calc_humidity (info->temp, info->dew);
430 gdouble t2 = temp * temp;
431 gdouble h2 = humidity * humidity;
432
433#if 1
434 /*
435 * A really precise formula. Note that overall precision is
436 * constrained by the accuracy of the instruments and that the
437 * we receive the temperature and dewpoints as integers.
438 */
439 gdouble t3 = t2 * temp;
440 gdouble h3 = h2 * temp;
441
442 apparent = 16.923
443 + 0.185212 * temp
444 + 5.37941 * humidity
445 - 0.100254 * temp * humidity
446 + 9.41695e-3 * t2
447 + 7.28898e-3 * h2
448 + 3.45372e-4 * t2 * humidity
449 - 8.14971e-4 * temp * h2
450 + 1.02102e-5 * t2 * h2
451 - 3.8646e-5 * t3
452 + 2.91583e-5 * h3
453 + 1.42721e-6 * t3 * humidity
454 + 1.97483e-7 * temp * h3
455 - 2.18429e-8 * t3 * h2
456 + 8.43296e-10 * t2 * h3
457 - 4.81975e-11 * t3 * h3;
458#else
459 /*
460 * An often cited alternative: values are within 5 degrees for
461 * most ranges between 10% and 70% humidity and to 110 degrees.
462 */
463 apparent = - 42.379
464 + 2.04901523 * temp
465 + 10.14333127 * humidity
466 - 0.22475541 * temp * humidity
467 - 6.83783e-3 * t2
468 - 5.481717e-2 * h2
469 + 1.22874e-3 * t2 * humidity
470 + 8.5282e-4 * temp * h2
471 - 1.99e-6 * t2 * h2;
472#endif
473 }
474 } else {
475 apparent = temp;
476 }
477
478 return apparent;
479}
480
481WeatherInfo *
482_weather_info_fill (WeatherInfo *info,
483 WeatherLocation *location,
484 const WeatherPrefs *prefs,
485 WeatherInfoFunc cb,
486 gpointer data)
487{
488 g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
489 ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (((info == ((void*)0)) && (location != ((void*)0
))) || ((info != ((void*)0)) && (location == ((void*)
0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1))) { } else { g_return_if_fail_warning ("MateWeather"
, ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))"
); return (((void*)0)); } } while (0)
;
490 g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "prefs != NULL")
; return (((void*)0)); } } while (0)
;
491
492 /* FIXME: i'm not sure this works as intended anymore */
493 if (!info) {
494 info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
495 info->requests_pending = 0;
496 info->location = weather_location_clone (location);
497 } else {
498 location = info->location;
499 if (info->forecast)
500 g_free (info->forecast);
501 info->forecast = NULL((void*)0);
502
503 free_forecast_list (info);
504
505 if (info->radar != NULL((void*)0)) {
506 g_object_unref (info->radar);
507 info->radar = NULL((void*)0);
508 }
509 }
510
511 /* Update in progress */
512 if (!requests_init (info)) {
513 return NULL((void*)0);
514 }
515
516 /* Defaults (just in case...) */
517 /* Well, no just in case anymore. We may actually fail to fetch some
518 * fields. */
519 info->forecast_type = prefs->type;
520
521 info->temperature_unit = prefs->temperature_unit;
522 info->speed_unit = prefs->speed_unit;
523 info->pressure_unit = prefs->pressure_unit;
524 info->distance_unit = prefs->distance_unit;
525
526 info->update = 0;
527 info->sky = -1;
528 info->cond.significant = FALSE(0);
529 info->cond.phenomenon = PHENOMENON_NONE;
530 info->cond.qualifier = QUALIFIER_NONE;
531 info->temp = -1000.0;
532 info->tempMinMaxValid = FALSE(0);
533 info->temp_min = -1000.0;
534 info->temp_max = -1000.0;
535 info->dew = -1000.0;
536 info->wind = -1;
537 info->windspeed = -1;
538 info->pressure = -1.0;
539 info->visibility = -1.0;
540 info->sunriseValid = FALSE(0);
541 info->sunsetValid = FALSE(0);
542 info->moonValid = FALSE(0);
543 info->sunrise = 0;
544 info->sunset = 0;
545 info->moonphase = 0;
546 info->moonlatitude = 0;
547 info->forecast = NULL((void*)0);
548 info->forecast_list = NULL((void*)0);
549 info->radar = NULL((void*)0);
550 info->radar_url = prefs->radar && prefs->radar_custom_url ?
551 g_strdup (prefs->radar_custom_url) : NULL((void*)0);
552 info->finish_cb = cb;
553 info->cb_data = data;
554
555 if (!info->session) {
556 info->session = soup_session_async_new ();
557 soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT(soup_proxy_resolver_default_get_type ()));
558 }
559
560 metar_start_open (info);
561 iwin_start_open (info);
562
563 if (prefs->radar) {
564 wx_start_open (info);
565 }
566
567 return info;
568}
569
570void
571weather_info_abort (WeatherInfo *info)
572{
573 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
574
575 if (info->session) {
576 soup_session_abort (info->session);
577 info->requests_pending = 0;
578 }
579}
580
581WeatherInfo *
582weather_info_clone (const WeatherInfo *info)
583{
584 WeatherInfo *clone;
585
586 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
587
588 clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p =
g_malloc (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s
); __p; }))
;
589
590
591 /* move everything */
592 memmove (clone, info, sizeof (WeatherInfo));
593
594
595 /* special moves */
596 clone->location = weather_location_clone (info->location);
597 /* This handles null correctly */
598 clone->forecast = g_strdup (info->forecast);
599 clone->radar_url = g_strdup (info->radar_url);
600
601 if (info->forecast_list) {
602 GSList *p;
603
604 clone->forecast_list = NULL((void*)0);
605 for (p = info->forecast_list; p; p = p->next) {
606 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
607 }
608
609 clone->forecast_list = g_slist_reverse (clone->forecast_list);
610 }
611
612 clone->radar = info->radar;
613 if (clone->radar != NULL((void*)0))
614 g_object_ref (clone->radar);
615
616 return clone;
617}
618
619void
620weather_info_free (WeatherInfo *info)
621{
622 if (!info)
623 return;
624
625 weather_info_abort (info);
626 if (info->session)
627 g_object_unref (info->session);
628
629 weather_location_free (info->location);
630 info->location = NULL((void*)0);
631
632 g_free (info->forecast);
633 info->forecast = NULL((void*)0);
634
635 free_forecast_list (info);
636
637 if (info->radar != NULL((void*)0)) {
638 g_object_unref (info->radar);
639 info->radar = NULL((void*)0);
640 }
641
642 g_free (info);
643}
644
645gboolean
646weather_info_is_valid (WeatherInfo *info)
647{
648 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
649 return info->valid;
650}
651
652gboolean
653weather_info_network_error (WeatherInfo *info)
654{
655 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
656 return info->network_error;
657}
658
659void
660weather_info_to_metric (WeatherInfo *info)
661{
662 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
663
664 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
665 info->speed_unit = SPEED_UNIT_MS;
666 info->pressure_unit = PRESSURE_UNIT_HPA;
667 info->distance_unit = DISTANCE_UNIT_METERS;
668}
669
670void
671weather_info_to_imperial (WeatherInfo *info)
672{
673 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
674
675 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
676 info->speed_unit = SPEED_UNIT_MPH;
677 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
678 info->distance_unit = DISTANCE_UNIT_MILES;
679}
680
681const WeatherLocation *
682weather_info_get_location (WeatherInfo *info)
683{
684 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
685 return info->location;
686}
687
688const gchar *
689weather_info_get_location_name (WeatherInfo *info)
690{
691 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
692 g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info->location != NULL"
); return (((void*)0)); } } while (0)
;
693 return info->location->name;
694}
695
696const gchar *
697weather_info_get_update (WeatherInfo *info)
698{
699 static gchar buf[200];
700 char *utf8, *timeformat;
701
702 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
703
704 if (!info->valid)
705 return "-";
706
707 if (info->update != 0) {
708 struct tm tm;
709 localtime_r (&info->update, &tm);
710 /* Translators: this is a format string for strftime
711 * see `man 3 strftime` for more details
712 */
713 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
714 NULL((void*)0), NULL((void*)0), NULL((void*)0));
715 if (!timeformat) {
716 strcpy (buf, "???");
717 }
718 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
719 strcpy (buf, "???");
720 }
721 g_free (timeformat);
722
723 /* Convert to UTF-8 */
724 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
725 strcpy (buf, utf8);
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
726 g_free (utf8);
727 } else {
728 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
729 buf[sizeof (buf)-1] = '\0';
730 }
731
732 return buf;
733}
734
735const gchar *
736weather_info_get_sky (WeatherInfo *info)
737{
738 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
739 if (!info->valid)
740 return "-";
741 if (info->sky < 0)
742 return _("Unknown")(mateweather_gettext ("Unknown"));
743 return weather_sky_string (info->sky);
744}
745
746const gchar *
747weather_info_get_conditions (WeatherInfo *info)
748{
749 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
750 if (!info->valid)
751 return "-";
752 return weather_conditions_string (info->cond);
753}
754
755static const gchar *
756temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
757{
758 static gchar buf[100];
759
760 switch (to_unit) {
761 case TEMP_UNIT_FAHRENHEIT:
762 if (!want_round) {
763 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
764 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
765 } else {
766 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
767 gdouble temp_r;
768
769 feclearexcept(range_problem);
770 temp_r = round (temp);
771 if (fetestexcept(range_problem))
772 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
773 else
774 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
775 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
776 }
777 break;
778 case TEMP_UNIT_CENTIGRADE:
779 if (!want_round) {
780 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
781 g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
782 } else {
783 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
784 gdouble temp_r;
785
786 feclearexcept(range_problem);
787 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
788 if (fetestexcept(range_problem))
789 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
790 else
791 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
792 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
793 }
794 break;
795 case TEMP_UNIT_KELVIN:
796 if (!want_round) {
797 /* Translators: This is the temperature in kelvin */
798 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
799 } else {
800 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
801 gdouble temp_r;
802
803 feclearexcept(range_problem);
804 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
805 if (fetestexcept(range_problem))
806 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
807 else
808 /* Translators: This is the temperature in kelvin */
809 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
810 }
811 break;
812
813 case TEMP_UNIT_INVALID:
814 case TEMP_UNIT_DEFAULT:
815 default:
816 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
817 return _("Unknown")(mateweather_gettext ("Unknown"));
818 }
819
820 return buf;
821}
822
823const gchar *
824weather_info_get_temp (WeatherInfo *info)
825{
826 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
827
828 if (!info->valid)
829 return "-";
830 if (info->temp < -500.0)
831 return _("Unknown")(mateweather_gettext ("Unknown"));
832
833 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
834}
835
836const gchar *
837weather_info_get_temp_min (WeatherInfo *info)
838{
839 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
840
841 if (!info->valid || !info->tempMinMaxValid)
842 return "-";
843 if (info->temp_min < -500.0)
844 return _("Unknown")(mateweather_gettext ("Unknown"));
845
846 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
847}
848
849const gchar *
850weather_info_get_temp_max (WeatherInfo *info)
851{
852 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
853
854 if (!info->valid || !info->tempMinMaxValid)
855 return "-";
856 if (info->temp_max < -500.0)
857 return _("Unknown")(mateweather_gettext ("Unknown"));
858
859 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
860}
861
862const gchar *
863weather_info_get_dew (WeatherInfo *info)
864{
865 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
866
867 if (!info->valid)
868 return "-";
869 if (info->dew < -500.0)
870 return _("Unknown")(mateweather_gettext ("Unknown"));
871
872 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
873}
874
875const gchar *
876weather_info_get_humidity (WeatherInfo *info)
877{
878 static gchar buf[20];
879 gdouble humidity;
880
881 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
882
883 if (!info->valid)
884 return "-";
885
886 humidity = calc_humidity (info->temp, info->dew);
887 if (humidity < 0.0)
888 return _("Unknown")(mateweather_gettext ("Unknown"));
889
890 /* Translators: This is the humidity in percent */
891 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
892 return buf;
893}
894
895const gchar *
896weather_info_get_apparent (WeatherInfo *info)
897{
898 gdouble apparent;
899
900 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
901 if (!info->valid)
902 return "-";
903
904 apparent = calc_apparent (info);
905 if (apparent < -500.0)
906 return _("Unknown")(mateweather_gettext ("Unknown"));
907
908 return temperature_string (apparent, info->temperature_unit, FALSE(0));
909}
910
911static const gchar *
912windspeed_string (gfloat knots, SpeedUnit to_unit)
913{
914 static gchar buf[100];
915
916 switch (to_unit) {
917 case SPEED_UNIT_KNOTS:
918 /* Translators: This is the wind speed in knots */
919 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
920 break;
921 case SPEED_UNIT_MPH:
922 /* Translators: This is the wind speed in miles per hour */
923 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
924 break;
925 case SPEED_UNIT_KPH:
926 /* Translators: This is the wind speed in kilometers per hour */
927 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
928 break;
929 case SPEED_UNIT_MS:
930 /* Translators: This is the wind speed in meters per second */
931 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
932 break;
933 case SPEED_UNIT_BFT:
934 /* Translators: This is the wind speed as a Beaufort force factor
935 * (commonly used in nautical wind estimation).
936 */
937 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
938 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
939 break;
940 case SPEED_UNIT_INVALID:
941 case SPEED_UNIT_DEFAULT:
942 default:
943 g_warning ("Conversion to illegal speed unit: %d", to_unit);
944 return _("Unknown")(mateweather_gettext ("Unknown"));
945 }
946
947 return buf;
948}
949
950const gchar *
951weather_info_get_wind (WeatherInfo *info)
952{
953 static gchar buf[200];
954
955 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
956
957 if (!info->valid)
958 return "-";
959 if (info->windspeed < 0.0 || info->wind < 0)
960 return _("Unknown")(mateweather_gettext ("Unknown"));
961 if (info->windspeed == 0.00) {
962 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
963 buf[sizeof (buf)-1] = '\0';
964 } else {
965 /* Translators: This is 'wind direction' / 'wind speed' */
966 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
967 weather_wind_direction_string (info->wind),
968 windspeed_string (info->windspeed, info->speed_unit));
969 }
970 return buf;
971}
972
973const gchar *
974weather_info_get_pressure (WeatherInfo *info)
975{
976 static gchar buf[100];
977
978 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
979
980 if (!info->valid)
981 return "-";
982 if (info->pressure < 0.0)
983 return _("Unknown")(mateweather_gettext ("Unknown"));
984
985 switch (info->pressure_unit) {
986 case PRESSURE_UNIT_INCH_HG:
987 /* Translators: This is pressure in inches of mercury */
988 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
989 break;
990 case PRESSURE_UNIT_MM_HG:
991 /* Translators: This is pressure in millimeters of mercury */
992 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
993 break;
994 case PRESSURE_UNIT_KPA:
995 /* Translators: This is pressure in kiloPascals */
996 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
997 break;
998 case PRESSURE_UNIT_HPA:
999 /* Translators: This is pressure in hectoPascals */
1000 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1001 break;
1002 case PRESSURE_UNIT_MB:
1003 /* Translators: This is pressure in millibars */
1004 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1005 break;
1006 case PRESSURE_UNIT_ATM:
1007 /* Translators: This is pressure in atmospheres */
1008 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1009 break;
1010
1011 case PRESSURE_UNIT_INVALID:
1012 case PRESSURE_UNIT_DEFAULT:
1013 default:
1014 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1015 return _("Unknown")(mateweather_gettext ("Unknown"));
1016 }
1017
1018 return buf;
1019}
1020
1021const gchar *
1022weather_info_get_visibility (WeatherInfo *info)
1023{
1024 static gchar buf[100];
1025
1026 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1027
1028 if (!info->valid)
1029 return "-";
1030 if (info->visibility < 0.0)
1031 return _("Unknown")(mateweather_gettext ("Unknown"));
1032
1033 switch (info->distance_unit) {
1034 case DISTANCE_UNIT_MILES:
1035 /* Translators: This is the visibility in miles */
1036 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1037 break;
1038 case DISTANCE_UNIT_KM:
1039 /* Translators: This is the visibility in kilometers */
1040 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1041 break;
1042 case DISTANCE_UNIT_METERS:
1043 /* Translators: This is the visibility in meters */
1044 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1045 break;
1046
1047 case DISTANCE_UNIT_INVALID:
1048 case DISTANCE_UNIT_DEFAULT:
1049 default:
1050 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1051 return _("Unknown")(mateweather_gettext ("Unknown"));
1052 }
1053
1054 return buf;
1055}
1056
1057const gchar *
1058weather_info_get_sunrise (WeatherInfo *info)
1059{
1060 static gchar buf[200];
1061 struct tm tm;
1062
1063 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1064
1065 if (!info->location->latlon_valid)
1066 return "-";
1067 if (!info->valid)
1068 return "-";
1069 if (!calc_sun (info))
1070 return "-";
1071
1072 localtime_r (&info->sunrise, &tm);
1073 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1074 return "-";
1075 return buf;
1076}
1077
1078const gchar *
1079weather_info_get_sunset (WeatherInfo *info)
1080{
1081 static gchar buf[200];
1082 struct tm tm;
1083
1084 g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info && info->location) _g_boolean_var_ = 1;
else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else
{ g_return_if_fail_warning ("MateWeather", ((const char*) (__func__
)), "info && info->location"); return (((void*)0))
; } } while (0)
;
1085
1086 if (!info->location->latlon_valid)
1087 return "-";
1088 if (!info->valid)
1089 return "-";
1090 if (!calc_sun (info))
1091 return "-";
1092
1093 localtime_r (&info->sunset, &tm);
1094 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1095 return "-";
1096 return buf;
1097}
1098
1099const gchar *
1100weather_info_get_forecast (WeatherInfo *info)
1101{
1102 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1103 return info->forecast;
1104}
1105
1106/**
1107 * weather_info_get_forecast_list:
1108 * Returns list of WeatherInfo* objects for the forecast.
1109 * The list is owned by the 'info' object thus is alive as long
1110 * as the 'info'. This list is filled only when requested with
1111 * type FORECAST_LIST and if available for given location.
1112 * The 'update' property is the date/time when the forecast info
1113 * is used for.
1114 **/
1115GSList *
1116weather_info_get_forecast_list (WeatherInfo *info)
1117{
1118 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1119
1120 if (!info->valid)
1121 return NULL((void*)0);
1122
1123 return info->forecast_list;
1124}
1125
1126GdkPixbufAnimation *
1127weather_info_get_radar (WeatherInfo *info)
1128{
1129 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1130 return info->radar;
1131}
1132
1133const gchar *
1134weather_info_get_temp_summary (WeatherInfo *info)
1135{
1136 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1137
1138 if (!info->valid || info->temp < -500.0)
1139 return "--";
1140
1141 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1142
1143}
1144
1145gchar *
1146weather_info_get_weather_summary (WeatherInfo *info)
1147{
1148 const gchar *buf;
1149
1150 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1151
1152 if (!info->valid)
1153 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1154 buf = weather_info_get_conditions (info);
1155 if (!strcmp (buf, "-"))
1156 buf = weather_info_get_sky (info);
1157 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1158}
1159
1160const gchar *
1161weather_info_get_icon_name (WeatherInfo *info)
1162{
1163 WeatherConditions cond;
1164 WeatherSky sky;
1165 time_t current_time;
1166 gboolean daytime;
1167 gchar* icon;
1168 static gchar icon_buffer[32];
1169 WeatherMoonPhase moonPhase;
1170 WeatherMoonLatitude moonLat;
1171 gint phase;
1172
1173 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1174
1175 if (!info->valid)
1176 return NULL((void*)0);
1177
1178 cond = info->cond;
1179 sky = info->sky;
1180
1181 if (cond.significant) {
1182 if (cond.phenomenon != PHENOMENON_NONE &&
1183 cond.qualifier == QUALIFIER_THUNDERSTORM)
1184 return "weather-storm";
1185
1186 switch (cond.phenomenon) {
1187 case PHENOMENON_INVALID:
1188 case PHENOMENON_LAST:
1189 case PHENOMENON_NONE:
1190 break;
1191
1192 case PHENOMENON_DRIZZLE:
1193 case PHENOMENON_RAIN:
1194 case PHENOMENON_UNKNOWN_PRECIPITATION:
1195 case PHENOMENON_HAIL:
1196 case PHENOMENON_SMALL_HAIL:
1197 return "weather-showers";
1198
1199 case PHENOMENON_SNOW:
1200 case PHENOMENON_SNOW_GRAINS:
1201 case PHENOMENON_ICE_PELLETS:
1202 case PHENOMENON_ICE_CRYSTALS:
1203 return "weather-snow";
1204
1205 case PHENOMENON_TORNADO:
1206 case PHENOMENON_SQUALL:
1207 return "weather-storm";
1208
1209 case PHENOMENON_MIST:
1210 case PHENOMENON_FOG:
1211 case PHENOMENON_SMOKE:
1212 case PHENOMENON_VOLCANIC_ASH:
1213 case PHENOMENON_SAND:
1214 case PHENOMENON_HAZE:
1215 case PHENOMENON_SPRAY:
1216 case PHENOMENON_DUST:
1217 case PHENOMENON_SANDSTORM:
1218 case PHENOMENON_DUSTSTORM:
1219 case PHENOMENON_FUNNEL_CLOUD:
1220 case PHENOMENON_DUST_WHIRLS:
1221 return "weather-fog";
1222 }
1223 }
1224
1225 if (info->midnightSun ||
1226 (!info->sunriseValid && !info->sunsetValid))
1227 daytime = TRUE(!(0));
1228 else if (info->polarNight)
1229 daytime = FALSE(0);
1230 else {
1231 current_time = time (NULL((void*)0));
1232 daytime =
1233 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1234 ( !info->sunsetValid || (current_time < info->sunset) );
1235 }
1236
1237 switch (sky) {
1238 case SKY_INVALID:
1239 case SKY_LAST:
1240 case SKY_CLEAR:
1241 if (daytime)
1242 return "weather-clear";
1243 else {
1244 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1245 break;
1246 }
1247
1248 case SKY_BROKEN:
1249 case SKY_SCATTERED:
1250 case SKY_FEW:
1251 if (daytime)
1252 return "weather-few-clouds";
1253 else {
1254 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1255 break;
1256 }
1257
1258 case SKY_OVERCAST:
1259 return "weather-overcast";
1260
1261 default: /* unrecognized */
1262 return NULL((void*)0);
1263 }
1264
1265 /*
1266 * A phase-of-moon icon is to be returned.
1267 * Determine which one based on the moon's location
1268 */
1269 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1270 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1271 if (phase == MOON_PHASES36) {
1272 phase = 0;
1273 } else if (phase > 0 &&
1274 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1275 < moonLat)) {
1276 /*
1277 * Locations south of the moon's latitude will see the moon in the
1278 * northern sky. The moon waxes and wanes from left to right
1279 * so we reference an icon running in the opposite direction.
1280 */
1281 phase = MOON_PHASES36 - phase;
1282 }
1283
1284 /*
1285 * If the moon is not full then append the angle to the icon string.
1286 * Note that an icon by this name is not required to exist:
1287 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1288 * the full moon image.
1289 */
1290 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1291 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1292 "-%03d", phase * 360 / MOON_PHASES36);
1293 }
1294 }
1295 return icon_buffer;
1296}
1297
1298static gboolean
1299temperature_value (gdouble temp_f,
1300 TempUnit to_unit,
1301 gdouble *value,
1302 TempUnit def_unit)
1303{
1304 gboolean ok = TRUE(!(0));
1305
1306 *value = 0.0;
1307 if (temp_f < -500.0)
1308 return FALSE(0);
1309
1310 if (to_unit == TEMP_UNIT_DEFAULT)
1311 to_unit = def_unit;
1312
1313 switch (to_unit) {
1314 case TEMP_UNIT_FAHRENHEIT:
1315 *value = temp_f;
1316 break;
1317 case TEMP_UNIT_CENTIGRADE:
1318 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1319 break;
1320 case TEMP_UNIT_KELVIN:
1321 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1322 break;
1323 case TEMP_UNIT_INVALID:
1324 case TEMP_UNIT_DEFAULT:
1325 default:
1326 ok = FALSE(0);
1327 break;
1328 }
1329
1330 return ok;
1331}
1332
1333static gboolean
1334speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1335{
1336 gboolean ok = TRUE(!(0));
1337
1338 *value = -1.0;
1339
1340 if (knots < 0.0)
1341 return FALSE(0);
1342
1343 if (to_unit == SPEED_UNIT_DEFAULT)
1344 to_unit = def_unit;
1345
1346 switch (to_unit) {
1347 case SPEED_UNIT_KNOTS:
1348 *value = knots;
1349 break;
1350 case SPEED_UNIT_MPH:
1351 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1352 break;
1353 case SPEED_UNIT_KPH:
1354 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1355 break;
1356 case SPEED_UNIT_MS:
1357 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1358 break;
1359 case SPEED_UNIT_BFT:
1360 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1361 break;
1362 case SPEED_UNIT_INVALID:
1363 case SPEED_UNIT_DEFAULT:
1364 default:
1365 ok = FALSE(0);
1366 break;
1367 }
1368
1369 return ok;
1370}
1371
1372static gboolean
1373pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1374{
1375 gboolean ok = TRUE(!(0));
1376
1377 *value = -1.0;
1378
1379 if (inHg < 0.0)
1380 return FALSE(0);
1381
1382 if (to_unit == PRESSURE_UNIT_DEFAULT)
1383 to_unit = def_unit;
1384
1385 switch (to_unit) {
1386 case PRESSURE_UNIT_INCH_HG:
1387 *value = inHg;
1388 break;
1389 case PRESSURE_UNIT_MM_HG:
1390 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1391 break;
1392 case PRESSURE_UNIT_KPA:
1393 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1394 break;
1395 case PRESSURE_UNIT_HPA:
1396 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1397 break;
1398 case PRESSURE_UNIT_MB:
1399 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1400 break;
1401 case PRESSURE_UNIT_ATM:
1402 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1403 break;
1404 case PRESSURE_UNIT_INVALID:
1405 case PRESSURE_UNIT_DEFAULT:
1406 default:
1407 ok = FALSE(0);
1408 break;
1409 }
1410
1411 return ok;
1412}
1413
1414static gboolean
1415distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1416{
1417 gboolean ok = TRUE(!(0));
1418
1419 *value = -1.0;
1420
1421 if (miles < 0.0)
1422 return FALSE(0);
1423
1424 if (to_unit == DISTANCE_UNIT_DEFAULT)
1425 to_unit = def_unit;
1426
1427 switch (to_unit) {
1428 case DISTANCE_UNIT_MILES:
1429 *value = miles;
1430 break;
1431 case DISTANCE_UNIT_KM:
1432 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1433 break;
1434 case DISTANCE_UNIT_METERS:
1435 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1436 break;
1437 case DISTANCE_UNIT_INVALID:
1438 case DISTANCE_UNIT_DEFAULT:
1439 default:
1440 ok = FALSE(0);
1441 break;
1442 }
1443
1444 return ok;
1445}
1446
1447gboolean
1448weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1449{
1450 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1451 g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "sky != NULL"); return
((0)); } } while (0)
;
1452
1453 if (!info->valid)
1454 return FALSE(0);
1455
1456 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1457 return FALSE(0);
1458
1459 *sky = info->sky;
1460
1461 return TRUE(!(0));
1462}
1463
1464gboolean
1465weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1466{
1467 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1468 g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phenomenon != NULL"
); return ((0)); } } while (0)
;
1469 g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "qualifier != NULL"
); return ((0)); } } while (0)
;
1470
1471 if (!info->valid)
1472 return FALSE(0);
1473
1474 if (!info->cond.significant)
1475 return FALSE(0);
1476
1477 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1478 info->cond.phenomenon < PHENOMENON_LAST &&
1479 info->cond.qualifier > QUALIFIER_INVALID &&
1480 info->cond.qualifier < QUALIFIER_LAST))
1481 return FALSE(0);
1482
1483 *phenomenon = info->cond.phenomenon;
1484 *qualifier = info->cond.qualifier;
1485
1486 return TRUE(!(0));
1487}
1488
1489gboolean
1490weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1491{
1492 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1493 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1494
1495 if (!info->valid)
1496 return FALSE(0);
1497
1498 return temperature_value (info->temp, unit, value, info->temperature_unit);
1499}
1500
1501gboolean
1502weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1503{
1504 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1505 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1506
1507 if (!info->valid || !info->tempMinMaxValid)
1508 return FALSE(0);
1509
1510 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1511}
1512
1513gboolean
1514weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1515{
1516 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1517 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1518
1519 if (!info->valid || !info->tempMinMaxValid)
1520 return FALSE(0);
1521
1522 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1523}
1524
1525gboolean
1526weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1527{
1528 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1529 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1530
1531 if (!info->valid)
1532 return FALSE(0);
1533
1534 return temperature_value (info->dew, unit, value, info->temperature_unit);
1535}
1536
1537gboolean
1538weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1539{
1540 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1541 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1542
1543 if (!info->valid)
1544 return FALSE(0);
1545
1546 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1547}
1548
1549gboolean
1550weather_info_get_value_update (WeatherInfo *info, time_t *value)
1551{
1552 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1553 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1554
1555 if (!info->valid)
1556 return FALSE(0);
1557
1558 *value = info->update;
1559
1560 return TRUE(!(0));
1561}
1562
1563gboolean
1564weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1565{
1566 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1567 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1568
1569 if (!info->valid || !info->sunriseValid)
1570 return FALSE(0);
1571
1572 *value = info->sunrise;
1573
1574 return TRUE(!(0));
1575}
1576
1577gboolean
1578weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1579{
1580 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1581 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1582
1583 if (!info->valid || !info->sunsetValid)
1584 return FALSE(0);
1585
1586 *value = info->sunset;
1587
1588 return TRUE(!(0));
1589}
1590
1591gboolean
1592weather_info_get_value_moonphase (WeatherInfo *info,
1593 WeatherMoonPhase *value,
1594 WeatherMoonLatitude *lat)
1595{
1596 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1597 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1598
1599 if (!info->valid || !info->moonValid)
1600 return FALSE(0);
1601
1602 *value = info->moonphase;
1603 *lat = info->moonlatitude;
1604
1605 return TRUE(!(0));
1606}
1607
1608gboolean
1609weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1610{
1611 gboolean res = FALSE(0);
1612
1613 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1614 g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "speed != NULL")
; return ((0)); } } while (0)
;
1615 g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "direction != NULL"
); return ((0)); } } while (0)
;
1616
1617 if (!info->valid)
1618 return FALSE(0);
1619
1620 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1621 return FALSE(0);
1622
1623 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1624 *direction = info->wind;
1625
1626 return res;
1627}
1628
1629gboolean
1630weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1631{
1632 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1633 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1634
1635 if (!info->valid)
1636 return FALSE(0);
1637
1638 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1639}
1640
1641gboolean
1642weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1643{
1644 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1645 g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "value != NULL")
; return ((0)); } } while (0)
;
1646
1647 if (!info->valid)
1648 return FALSE(0);
1649
1650 return distance_value (info->visibility, unit, value, info->distance_unit);
1651}
1652
1653/**
1654 * weather_info_get_upcoming_moonphases:
1655 * @info: WeatherInfo containing the time_t of interest
1656 * @phases: An array of four time_t values that will hold the returned values.
1657 * The values are estimates of the time of the next new, quarter, full and
1658 * three-quarter moons.
1659 *
1660 * Returns: gboolean indicating success or failure
1661 */
1662gboolean
1663weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1664{
1665 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1666 g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "phases != NULL"
); return ((0)); } } while (0)
;
1667
1668 return calc_moon_phases(info, phases);
1669}
1670
1671static void
1672_weather_internal_check (void)
1673{
1674 g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str
)[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1674, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1675 g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST)
_g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c"
, 1675, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1676 g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0])
) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1677 g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_
; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0
])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr
("MateWeather", "weather.c", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1678}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-b5d653.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-b5d653.html new file mode 100644 index 0000000..27d5f5b --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-b5d653.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 339, column 12
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
This statement is never executed
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-cbdc18.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-cbdc18.html new file mode 100644 index 0000000..dddbaab --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-cbdc18.html @@ -0,0 +1,705 @@ + + + +weather-sun.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-sun.c
Warning:line 164, column 13
Value stored to 'obsLat' during its initialization is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-sun.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather-sun.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-sun.c - Astronomy calculations for mateweather
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Formulas from:
21 * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
22 * Cambridge University Press 1988
23 * Unless otherwise noted, comments referencing "steps" are related to
24 * the algorithm presented in section 49 of above
25 */
26
27#ifdef HAVE_CONFIG_H1
28#include <config.h>
29#endif
30
31#include <math.h>
32#include <time.h>
33#include <glib.h>
34
35#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
36#include "weather-priv.h"
37
38#define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392)
39
40/*
41 * Ecliptic longitude of the sun at specified time (UT)
42 * The algoithm is described in section 47 of Duffett-Smith
43 * Return value is in radians
44 */
45gdouble
46sunEclipLongitude(time_t t)
47{
48 gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
49
50 /*
51 * Start with an estimate based on a fixed daily rate
52 */
53 ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.;
54 meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
55 - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193
+ (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846
)
;
56
57 /*
58 * Approximate solution of Kepler's equation:
59 * Find E which satisfies E - e sin(E) = M (mean anomaly)
60 */
61 eccenAnom = meanAnom;
62 e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392);
63
64 while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
65 {
66 eccenAnom -= delta / (1.- e * cos(eccenAnom));
67 }
68
69 /*
70 * Earth's longitude on the ecliptic
71 */
72 longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.
) * 3.14159265358979323846)
73 + 2. * atan (sqrt ((1.+e)/(1.-e))
74 * tan (eccenAnom / 2.)),
75 2. * M_PI3.14159265358979323846);
76 if (longitude < 0.) {
77 longitude += 2 * M_PI3.14159265358979323846;
78 }
79 return longitude;
80}
81
82static gdouble
83ecliptic_obliquity (gdouble time)
84{
85 gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.);
86 gdouble eclip_secs = (84381.448
87 - (46.84024 * jc)
88 - (59.e-5 * jc * jc)
89 + (1.813e-3 * jc * jc * jc));
90 return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846
)
;
91}
92
93/*
94 * Convert ecliptic longitude and latitude (radians) to equitorial
95 * coordinates, expressed as right ascension (hours) and
96 * declination (radians)
97 */
98void
99ecl2equ (gdouble time,
100 gdouble eclipLon, gdouble eclipLat,
101 gdouble *ra, gdouble *decl)
102{
103 gdouble mEclipObliq = ecliptic_obliquity(time);
104
105 if (ra) {
106 *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
107 - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
108 cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat)
* sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846
)
;
109 if (*ra < 0.)
110 *ra += 24.;
111 }
112 if (decl) {
113 *decl = asin (( sin (eclipLat) * cos (mEclipObliq))
114 + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
115 }
116}
117
118/*
119 * Calculate rising and setting times for an object
120 * based on it equitorial coordinates (section 33 & 15)
121 * Returned "rise" and "set" values are sideral times in hours
122 */
123static void
124gstObsv (gdouble ra, gdouble decl,
125 gdouble obsLat, gdouble obsLon,
126 gdouble *rise, gdouble *set)
127{
128 double a = acos (-tan (obsLat) * tan (decl));
129 double b;
130
131 if (isnan (a)__builtin_isnan (a) != 0) {
132 *set = *rise = a;
133 return;
134 }
135 a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846);
136 b = 24. - a + ra;
137 a += ra;
138 a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
139 b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846);
140 if ((a = fmod (a, 24.)) < 0)
141 a += 24.;
142 if ((b = fmod (b, 24.)) < 0)
143 b += 24.;
144
145 *set = a;
146 *rise = b;
147}
148
149
150static gdouble
151t0 (time_t date)
152{
153 gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0;
154 gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
155 if (t0 < 0.)
156 t0 += 24.;
157 return t0;
158}
159
160
161static gboolean
162calc_sun2 (WeatherInfo *info, time_t t)
163{
164 gdouble obsLat = info->location->latitude;
Value stored to 'obsLat' during its initialization is never read
165 gdouble obsLon = info->location->longitude;
166 time_t gm_midn;
167 time_t lcl_midn;
168 gdouble gm_hoff, lambda;
169 gdouble ra1, ra2;
170 gdouble decl1, decl2;
171 gdouble decl_midn, decl_noon;
172 gdouble rise1, rise2;
173 gdouble set1, set2;
174 gdouble tt, t00;
175 gdouble x, u, dt;
176
177 /* Approximate preceding local midnight at observer's longitude */
178 obsLat = info->location->latitude;
179 obsLon = info->location->longitude;
180 gm_midn = t - (t % 86400);
181 gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.);
182 lcl_midn = gm_midn - 3600. * gm_hoff;
183 if (t - lcl_midn >= 86400)
184 lcl_midn += 86400;
185 else if (lcl_midn > t)
186 lcl_midn -= 86400;
187
188 lambda = sunEclipLongitude (lcl_midn);
189
190 /*
191 * Calculate equitorial coordinates of sun at previous
192 * and next local midnights
193 */
194 ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
195 ecl2equ (lcl_midn + 86400.,
196 lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846
)
, 0.,
197 &ra2, &decl2);
198
199 /*
200 * If the observer is within the Arctic or Antarctic Circles then
201 * the sun may be above or below the horizon for the full day.
202 */
203 decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2));
204 decl_noon = (decl1+decl2)/2.;
205 info->midnightSun =
206 (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn));
207 info->polarNight =
208 (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon));
209 if (info->midnightSun || info->polarNight) {
210 info->sunriseValid = info->sunsetValid = FALSE(0);
211 return FALSE(0);
212 }
213
214 /*
215 * Convert to rise and set times based positions for the preceding
216 * and following local midnights.
217 */
218 gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1);
219 gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2);
220
221 /* TODO: include calculations for regions near the poles. */
222 if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) {
223 info->sunriseValid = info->sunsetValid = FALSE(0);
224 return FALSE(0);
225 }
226
227 if (rise2 < rise1) {
228 rise2 += 24.;
229 }
230 if (set2 < set1) {
231 set2 += 24.;
232 }
233
234 tt = t0(lcl_midn);
235 t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909;
236
237 if (t00 < 0.)
238 t00 += 24.;
239
240 if (rise1 < t00) {
241 rise1 += 24.;
242 rise2 += 24.;
243 }
244 if (set1 < t00) {
245 set1 += 24.;
246 set2 += 24.;
247 }
248
249 /*
250 * Interpolate between the two to get a rise and set time
251 * based on the sun's position at local noon (step 8)
252 */
253 rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
254 set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
255
256 /*
257 * Calculate an adjustment value to account for parallax,
258 * refraction and the Sun's finite diameter (steps 9,10)
259 */
260 decl2 = (decl1 + decl2) / 2.;
261 x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846);
262 u = acos ( sin(obsLat) / cos(decl2) );
263 dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846
)
;
264
265 /*
266 * Subtract the correction value from sunrise and add to sunset,
267 * then (step 11) convert sideral times to UT
268 */
269 rise1 = (rise1 - dt - tt) * 0.9972695661;
270 if (rise1 < 0.)
271 rise1 += 24;
272 else if (rise1 >= 24.)
273 rise1 -= 24.;
274 info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
275 info->sunrise = (rise1 * 3600.) + lcl_midn;
276
277 set1 = (set1 + dt - tt) * 0.9972695661;
278 if (set1 < 0.)
279 set1 += 24;
280 else if (set1 >= 24.)
281 set1 -= 24.;
282 info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
283 info->sunset = (set1 * 3600.) + lcl_midn;
284
285 return (info->sunriseValid || info->sunsetValid);
286}
287
288
289/**
290 * calc_sun_time:
291 * @info: #WeatherInfo structure containing the observer's latitude
292 * and longitude in radians, fills in the sunrise and sunset times.
293 * @t: time_t
294 *
295 * Returns: gboolean indicating if the results are valid.
296 */
297gboolean
298calc_sun_time (WeatherInfo *info, time_t t)
299{
300 return info->location->latlon_valid && calc_sun2 (info, t);
301}
302
303/**
304 * calc_sun:
305 * @info: #WeatherInfo structure containing the observer's latitude
306 * and longitude in radians, fills in the sunrise and sunset times.
307 *
308 * Returns: gboolean indicating if the results are valid.
309 */
310gboolean
311calc_sun (WeatherInfo *info)
312{
313 return calc_sun_time(info, time(NULL((void*)0)));
314}
315
316
317/**
318 * weather_info_next_sun_event:
319 * @info: #WeatherInfo structure
320 *
321 * Returns: the interval, in seconds, until the next "sun event":
322 * - local midnight, when rise and set times are recomputed
323 * - next sunrise, when icon changes to daytime version
324 * - next sunset, when icon changes to nighttime version
325 */
326gint
327weather_info_next_sun_event (WeatherInfo *info)
328{
329 time_t now = time (NULL((void*)0));
330 struct tm ltm;
331 time_t nxtEvent;
332
333 g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (-1); } } while (0)
;
334
335 if (!calc_sun (info))
336 return -1;
337
338 /* Determine when the next local midnight occurs */
339 (void) localtime_r (&now, &ltm);
340 ltm.tm_sec = 0;
341 ltm.tm_min = 0;
342 ltm.tm_hour = 0;
343 ltm.tm_mday++;
344 nxtEvent = mktime (&ltm);
345
346 if (info->sunsetValid &&
347 (info->sunset > now) && (info->sunset < nxtEvent))
348 nxtEvent = info->sunset;
349 if (info->sunriseValid &&
350 (info->sunrise > now) && (info->sunrise < nxtEvent))
351 nxtEvent = info->sunrise;
352 return (gint)(nxtEvent - now);
353}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-dc17ea.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-dc17ea.html new file mode 100644 index 0000000..edd683c --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-dc17ea.html @@ -0,0 +1,557 @@ + + + +weather-met.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-met.c
Warning:line 111, column 8
Dereference of null pointer (loaded from variable 'o')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-met.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather-met.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-met.c - UK Met Office forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
28#include "weather.h"
29#include "weather-priv.h"
30
31static char *
32met_reprocess (char *x, int len)
33{
34 char *p = x;
35 char *o;
36 int spacing = 0;
37 static gchar *buf;
22
'buf' initialized to a null pointer value
38 static gint buflen = 0;
39 gchar *lastspace = NULL((void*)0);
40 int count = 0;
41
42 if (buflen < len)
23
Assuming 'buflen' is >= 'len'
24
Taking false branch
43 {
44 if (buf)
45 g_free (buf);
46 buf = g_malloc (len + 1);
47 buflen = len;
48 }
49
50 o = buf;
25
Null pointer value stored to 'o'
51 x += len; /* End mark */
52
53 while (*p && p < x) {
26
Assuming the condition is false
54 if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) {
55 if (!spacing) {
56 spacing = 1;
57 lastspace = o;
58 count++;
59 *o++ = ' ';
60 }
61 p++;
62 continue;
63 }
64 spacing = 0;
65 if (count > 75 && lastspace) {
66 count = o - lastspace - 1;
67 *lastspace = '\n';
68 lastspace = NULL((void*)0);
69 }
70
71 if (*p == '&') {
72 if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
73 *o++ = '&';
74 count++;
75 p += 5;
76 continue;
77 }
78 if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
79 *o++ = '<';
80 count++;
81 p += 4;
82 continue;
83 }
84 if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
85 *o++ = '>';
86 count++;
87 p += 4;
88 continue;
89 }
90 }
91 if (*p == '<') {
92 if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
93 *o++ = '\n';
94 count = 0;
95 }
96 if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
97 *o++ = '\n';
98 *o++ = '\n';
99 count = 0;
100 }
101 p++;
102 while (*p && *p != '>')
103 p++;
104 if (*p)
105 p++;
106 continue;
107 }
108 *o++ = *p++;
109 count++;
110 }
111 *o = 0;
27
Dereference of null pointer (loaded from variable 'o')
112 return buf;
113}
114
115
116/*
117 * Parse the metoffice forecast info.
118 * For mate 3.0 we want to just embed an HTML matecomponent component and
119 * be done with this ;)
120 */
121
122static gchar *
123met_parse (const gchar *meto)
124{
125 gchar *p;
126 gchar *rp;
127 gchar *r = g_strdup ("Met Office Forecast\n");
128 gchar *t;
129
130 g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "meto != NULL");
return (r); } } while (0)
;
9
Assuming 'meto' is not equal to null
10
Taking true branch
11
Taking true branch
12
Loop condition is false. Exiting loop
131
132 p = strstr (meto, "Summary: </b>");
133 g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "p != NULL"); return
(r); } } while (0)
;
13
Assuming 'p' is not equal to null
14
Taking true branch
15
Taking true branch
16
Loop condition is false. Exiting loop
134
135 rp = strstr (p, "Text issued at:");
136 g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "rp != NULL"); return
(r); } } while (0)
;
17
Assuming 'rp' is not equal to null
18
Taking true branch
19
Taking true branch
20
Loop condition is false. Exiting loop
137
138 p += 13;
139 /* p to rp is the text block we want but in HTML malformat */
140 t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0));
21
Calling 'met_reprocess'
141 g_free (r);
142
143 return t;
144}
145
146static void
147met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
148{
149 WeatherInfo *info = (WeatherInfo *)data;
150
151 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
1
Assuming 'info' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
152
153 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
5
Assuming field 'status_code' is >= 200
6
Assuming field 'status_code' is < 300
7
Taking false branch
154 g_warning ("Failed to get Met Office forecast data: %d %s.\n",
155 msg->status_code, msg->reason_phrase);
156 request_done (info, FALSE(0));
157 return;
158 }
159
160 info->forecast = met_parse (msg->response_body->data);
8
Calling 'met_parse'
161 request_done (info, TRUE(!(0)));
162}
163
164void
165metoffice_start_open (WeatherInfo *info)
166{
167 gchar *url;
168 SoupMessage *msg;
169 WeatherLocation *loc;
170
171 loc = info->location;
172 url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
173
174 msg = soup_message_new ("GET", url);
175 soup_session_queue_message (info->session, msg, met_finish, info);
176 g_free (url);
177
178 info->requests_pending++;
179}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-e56eb8.html b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-e56eb8.html new file mode 100644 index 0000000..37ab8d7 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/report-e56eb8.html @@ -0,0 +1,917 @@ + + + +weather-metar.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather-metar.c
Warning:line 177, column 28
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name weather-metar.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/libxml2 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/at-spi-2.0 -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-2.4 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="MateWeather" -D MATELOCALEDIR="/usr/local/share/locale" -D MATEWEATHER_XML_LOCATION_DIR="/usr/local/share/libmateweather" -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-sign-compare -fdebug-compilation-dir /rootdir/libmateweather -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -o /rootdir/html-report/2020-12-10-200341-5831-1 -x c weather-metar.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-metar.c - Weather server functions (METAR)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <regex.h>
27
28#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
29#include "weather.h"
30#include "weather-priv.h"
31
32enum {
33 TIME_RE,
34 WIND_RE,
35 VIS_RE,
36 COND_RE,
37 CLOUD_RE,
38 TEMP_RE,
39 PRES_RE,
40
41 RE_NUM
42};
43
44/* Return time of weather report as secs since epoch UTC */
45static time_t
46make_time (gint utcDate, gint utcHour, gint utcMin)
47{
48 const time_t now = time (NULL((void*)0));
49 struct tm tm;
50
51 localtime_r (&now, &tm);
52
53 /* If last reading took place just before midnight UTC on the
54 * first, adjust the date downward to allow for the month
55 * change-over. This ASSUMES that the reading won't be more than
56 * 24 hrs old! */
57 if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
58 tm.tm_mday = 0; /* mktime knows this is the last day of the previous
59 * month. */
60 } else {
61 tm.tm_mday = utcDate;
62 }
63 tm.tm_hour = utcHour;
64 tm.tm_min = utcMin;
65 tm.tm_sec = 0;
66
67 /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
68#ifdef HAVE_TM_TM_GMOFF1
69 return tm.tm_gmtoff + mktime (&tm);
70#elif defined HAVE_TIMEZONE
71 return timezone + mktime (&tm);
72#endif
73}
74
75static void
76metar_tok_time (gchar *tokp, WeatherInfo *info)
77{
78 gint day, hr, min;
79
80 sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
81 info->update = make_time (day, hr, min);
82}
83
84static void
85metar_tok_wind (gchar *tokp, WeatherInfo *info)
86{
87 gchar sdir[4], sspd[4], sgust[4];
88 gint dir, spd = -1;
89 gchar *gustp;
90 size_t glen;
91
92 strncpy (sdir, tokp, 3);
93 sdir[3] = 0;
94 dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
95
96 memset (sspd, 0, sizeof (sspd));
97 glen = strspn (tokp + 3, CONST_DIGITS"0123456789");
98 strncpy (sspd, tokp + 3, glen);
99 spd = atoi (sspd);
100 tokp += glen + 3;
101
102 gustp = strchr (tokp, 'G');
103 if (gustp) {
104 memset (sgust, 0, sizeof (sgust));
105 glen = strspn (gustp + 1, CONST_DIGITS"0123456789");
106 strncpy (sgust, gustp + 1, glen);
107 tokp = gustp + 1 + glen;
108 }
109
110 if (!strcmp (tokp, "MPS"))
111 info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444);
112 else
113 info->windspeed = (WeatherWindSpeed)spd;
114
115 if ((349 <= dir) || (dir <= 11))
116 info->wind = WIND_N;
117 else if ((12 <= dir) && (dir <= 33))
118 info->wind = WIND_NNE;
119 else if ((34 <= dir) && (dir <= 56))
120 info->wind = WIND_NE;
121 else if ((57 <= dir) && (dir <= 78))
122 info->wind = WIND_ENE;
123 else if ((79 <= dir) && (dir <= 101))
124 info->wind = WIND_E;
125 else if ((102 <= dir) && (dir <= 123))
126 info->wind = WIND_ESE;
127 else if ((124 <= dir) && (dir <= 146))
128 info->wind = WIND_SE;
129 else if ((147 <= dir) && (dir <= 168))
130 info->wind = WIND_SSE;
131 else if ((169 <= dir) && (dir <= 191))
132 info->wind = WIND_S;
133 else if ((192 <= dir) && (dir <= 213))
134 info->wind = WIND_SSW;
135 else if ((214 <= dir) && (dir <= 236))
136 info->wind = WIND_SW;
137 else if ((237 <= dir) && (dir <= 258))
138 info->wind = WIND_WSW;
139 else if ((259 <= dir) && (dir <= 281))
140 info->wind = WIND_W;
141 else if ((282 <= dir) && (dir <= 303))
142 info->wind = WIND_WNW;
143 else if ((304 <= dir) && (dir <= 326))
144 info->wind = WIND_NW;
145 else if ((327 <= dir) && (dir <= 348))
146 info->wind = WIND_NNW;
147}
148
149static void
150metar_tok_vis (gchar *tokp, WeatherInfo *info)
151{
152 gchar *pfrac, *pend, *psp;
153 gchar sval[6];
154 gint num, den, val;
155
156 memset (sval, 0, sizeof (sval));
157
158 if (!strcmp (tokp,"CAVOK")) {
159 // "Ceiling And Visibility OK": visibility >= 10 KM
160 info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
161 info->sky = SKY_CLEAR;
162 } else if (0 != (pend = strstr (tokp, "SM"))) {
163 // US observation: field ends with "SM"
164 pfrac = strchr (tokp, '/');
165 if (pfrac) {
166 if (*tokp == 'M') {
167 info->visibility = 0.001;
168 } else {
169 num = (*(pfrac - 1) - '0');
170 strncpy (sval, pfrac + 1, pend - pfrac - 1);
171 den = atoi (sval);
172 info->visibility =
173 ((WeatherVisibility)num / ((WeatherVisibility)den));
174
175 psp = strchr (tokp, ' ');
176 if (psp) {
177 *psp = '\0';
This statement is never executed
178 val = atoi (tokp);
179 info->visibility += (WeatherVisibility)val;
180 }
181 }
182 } else {
183 strncpy (sval, tokp, pend - tokp);
184 val = atoi (sval);
185 info->visibility = (WeatherVisibility)val;
186 }
187 } else {
188 // International observation: NNNN(DD NNNNDD)?
189 // For now: use only the minimum visibility and ignore its direction
190 strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789"));
191 val = atoi (sval);
192 info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000);
193 }
194}
195
196static void
197metar_tok_cloud (gchar *tokp, WeatherInfo *info)
198{
199 gchar stype[4], salt[4];
200
201 strncpy (stype, tokp, 3);
202 stype[3] = 0;
203 if (strlen (tokp) == 6) {
204 strncpy (salt, tokp + 3, 3);
205 salt[3] = 0;
206 }
207
208 if (!strcmp (stype, "CLR")) {
209 info->sky = SKY_CLEAR;
210 } else if (!strcmp (stype, "SKC")) {
211 info->sky = SKY_CLEAR;
212 } else if (!strcmp (stype, "NSC")) {
213 info->sky = SKY_CLEAR;
214 } else if (!strcmp (stype, "BKN")) {
215 info->sky = SKY_BROKEN;
216 } else if (!strcmp (stype, "SCT")) {
217 info->sky = SKY_SCATTERED;
218 } else if (!strcmp (stype, "FEW")) {
219 info->sky = SKY_FEW;
220 } else if (!strcmp (stype, "OVC")) {
221 info->sky = SKY_OVERCAST;
222 }
223}
224
225static void
226metar_tok_pres (gchar *tokp, WeatherInfo *info)
227{
228 if (*tokp == 'A') {
229 gchar sintg[3], sfract[3];
230 gint intg, fract;
231
232 strncpy (sintg, tokp + 1, 2);
233 sintg[2] = 0;
234 intg = atoi (sintg);
235
236 strncpy (sfract, tokp + 3, 2);
237 sfract[2] = 0;
238 fract = atoi (sfract);
239
240 info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
241 } else { /* *tokp == 'Q' */
242 gchar spres[5];
243 gint pres;
244
245 strncpy (spres, tokp + 1, 4);
246 spres[4] = 0;
247 pres = atoi (spres);
248
249 info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373);
250 }
251}
252
253static void
254metar_tok_temp (gchar *tokp, WeatherInfo *info)
255{
256 gchar *ptemp, *pdew, *psep;
257
258 psep = strchr (tokp, '/');
259 *psep = 0;
260 ptemp = tokp;
261 pdew = psep + 1;
262
263 info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0)
264 : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0);
265 if (*pdew) {
266 info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0)
267 : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0);
268 } else {
269 info->dew = -1000.0;
270 }
271}
272
273static void
274metar_tok_cond (gchar *tokp, WeatherInfo *info)
275{
276 gchar squal[3], sphen[4];
277 gchar *pphen;
278
279 if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
280 ++tokp; /* FIX */
281
282 if ((*tokp == '+') || (*tokp == '-'))
283 pphen = tokp + 1;
284 else if (strlen (tokp) < 4)
285 pphen = tokp;
286 else
287 pphen = tokp + 2;
288
289 memset (squal, 0, sizeof (squal));
290 strncpy (squal, tokp, pphen - tokp);
291 squal[pphen - tokp] = 0;
292
293 memset (sphen, 0, sizeof (sphen));
294 strncpy (sphen, pphen, sizeof (sphen));
295 sphen[sizeof (sphen)-1] = '\0';
296
297 /* Defaults */
298 info->cond.qualifier = QUALIFIER_NONE;
299 info->cond.phenomenon = PHENOMENON_NONE;
300 info->cond.significant = FALSE(0);
301
302 if (!strcmp (squal, "")) {
303 info->cond.qualifier = QUALIFIER_MODERATE;
304 } else if (!strcmp (squal, "-")) {
305 info->cond.qualifier = QUALIFIER_LIGHT;
306 } else if (!strcmp (squal, "+")) {
307 info->cond.qualifier = QUALIFIER_HEAVY;
308 } else if (!strcmp (squal, "VC")) {
309 info->cond.qualifier = QUALIFIER_VICINITY;
310 } else if (!strcmp (squal, "MI")) {
311 info->cond.qualifier = QUALIFIER_SHALLOW;
312 } else if (!strcmp (squal, "BC")) {
313 info->cond.qualifier = QUALIFIER_PATCHES;
314 } else if (!strcmp (squal, "PR")) {
315 info->cond.qualifier = QUALIFIER_PARTIAL;
316 } else if (!strcmp (squal, "TS")) {
317 info->cond.qualifier = QUALIFIER_THUNDERSTORM;
318 } else if (!strcmp (squal, "BL")) {
319 info->cond.qualifier = QUALIFIER_BLOWING;
320 } else if (!strcmp (squal, "SH")) {
321 info->cond.qualifier = QUALIFIER_SHOWERS;
322 } else if (!strcmp (squal, "DR")) {
323 info->cond.qualifier = QUALIFIER_DRIFTING;
324 } else if (!strcmp (squal, "FZ")) {
325 info->cond.qualifier = QUALIFIER_FREEZING;
326 } else {
327 return;
328 }
329
330 if (!strcmp (sphen, "DZ")) {
331 info->cond.phenomenon = PHENOMENON_DRIZZLE;
332 } else if (!strcmp (sphen, "RA")) {
333 info->cond.phenomenon = PHENOMENON_RAIN;
334 } else if (!strcmp (sphen, "SN")) {
335 info->cond.phenomenon = PHENOMENON_SNOW;
336 } else if (!strcmp (sphen, "SG")) {
337 info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
338 } else if (!strcmp (sphen, "IC")) {
339 info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
340 } else if (!strcmp (sphen, "PE")) {
341 info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
342 } else if (!strcmp (sphen, "GR")) {
343 info->cond.phenomenon = PHENOMENON_HAIL;
344 } else if (!strcmp (sphen, "GS")) {
345 info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
346 } else if (!strcmp (sphen, "UP")) {
347 info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
348 } else if (!strcmp (sphen, "BR")) {
349 info->cond.phenomenon = PHENOMENON_MIST;
350 } else if (!strcmp (sphen, "FG")) {
351 info->cond.phenomenon = PHENOMENON_FOG;
352 } else if (!strcmp (sphen, "FU")) {
353 info->cond.phenomenon = PHENOMENON_SMOKE;
354 } else if (!strcmp (sphen, "VA")) {
355 info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
356 } else if (!strcmp (sphen, "SA")) {
357 info->cond.phenomenon = PHENOMENON_SAND;
358 } else if (!strcmp (sphen, "HZ")) {
359 info->cond.phenomenon = PHENOMENON_HAZE;
360 } else if (!strcmp (sphen, "PY")) {
361 info->cond.phenomenon = PHENOMENON_SPRAY;
362 } else if (!strcmp (sphen, "DU")) {
363 info->cond.phenomenon = PHENOMENON_DUST;
364 } else if (!strcmp (sphen, "SQ")) {
365 info->cond.phenomenon = PHENOMENON_SQUALL;
366 } else if (!strcmp (sphen, "SS")) {
367 info->cond.phenomenon = PHENOMENON_SANDSTORM;
368 } else if (!strcmp (sphen, "DS")) {
369 info->cond.phenomenon = PHENOMENON_DUSTSTORM;
370 } else if (!strcmp (sphen, "PO")) {
371 info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
372 } else if (!strcmp (sphen, "+FC")) {
373 info->cond.phenomenon = PHENOMENON_TORNADO;
374 } else if (!strcmp (sphen, "FC")) {
375 info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
376 } else {
377 return;
378 }
379
380 if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
381 info->cond.significant = TRUE(!(0));
382}
383
384#define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z"
385#define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
386#define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
387 "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
388 "CAVOK"
389#define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
390#define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
391#define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
392#define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})"
393
394/* POSIX regular expressions do not allow us to express "match whole words
395 * only" in a simple way, so we have to wrap them all into
396 * (^| )(...regex...)( |$)
397 */
398#define RE_PREFIX"(^| )(" "(^| )("
399#define RE_SUFFIX")( |$)" ")( |$)"
400
401static regex_t metar_re[RE_NUM];
402static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
403
404static void
405metar_init_re (void)
406{
407 static gboolean initialized = FALSE(0);
408 if (initialized)
409 return;
410 initialized = TRUE(!(0));
411
412 regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1);
413 regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1);
414 regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|"
"CAVOK"
RE_SUFFIX")( |$)", REG_EXTENDED1);
415 regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1);
416 regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
417 regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1);
418 regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1);
419
420 metar_f[TIME_RE] = metar_tok_time;
421 metar_f[WIND_RE] = metar_tok_wind;
422 metar_f[VIS_RE] = metar_tok_vis;
423 metar_f[COND_RE] = metar_tok_cond;
424 metar_f[CLOUD_RE] = metar_tok_cloud;
425 metar_f[TEMP_RE] = metar_tok_temp;
426 metar_f[PRES_RE] = metar_tok_pres;
427}
428
429gboolean
430metar_parse (gchar *metar, WeatherInfo *info)
431{
432 gchar *p;
433 //gchar *rmk;
434 gint i, i2;
435 regmatch_t rm, rm2;
436 gchar *tokp;
437
438 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
439 g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "metar != NULL")
; return ((0)); } } while (0)
;
440
441 metar_init_re ();
442
443 /*
444 * Force parsing to end at "RMK" field. This prevents a subtle
445 * problem when info within the remark happens to match an earlier state
446 * and, as a result, throws off all the remaining expression
447 */
448 if (0 != (p = strstr (metar, " RMK "))) {
449 *p = '\0';
450 //rmk = p + 5; // uncomment this if RMK data becomes useful
451 }
452
453 p = metar;
454 i = TIME_RE;
455 while (*p) {
456
457 i2 = RE_NUM;
458 rm2.rm_so = strlen (p);
459 rm2.rm_eo = rm2.rm_so;
460
461 for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
462 if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
463 && rm.rm_so < rm2.rm_so)
464 {
465 i2 = i;
466 /* Skip leading and trailing space characters, if present.
467 (the regular expressions include those characters to
468 only get matches limited to whole words). */
469 if (p[rm.rm_so] == ' ') rm.rm_so++;
470 if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
471 rm2.rm_so = rm.rm_so;
472 rm2.rm_eo = rm.rm_eo;
473 }
474 }
475
476 if (i2 != RE_NUM) {
477 tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
478 metar_f[i2] (tokp, info);
479 g_free (tokp);
480 }
481
482 p += rm2.rm_eo;
483 p += strspn (p, " ");
484 }
485 return TRUE(!(0));
486}
487
488static void
489metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
490{
491 WeatherInfo *info = (WeatherInfo *)data;
492 WeatherLocation *loc;
493 const gchar *p, *endtag;
494 gchar *searchkey, *metar;
495 gboolean success = FALSE(0);
496
497 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
498
499 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code
) < 300)
) {
500 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code
) < 100)
)
501 info->network_error = TRUE(!(0));
502 else {
503 /* Translators: %d is an error code, and %s the error string */
504 g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")),
505 msg->status_code, msg->reason_phrase);
506 }
507 request_done (info, FALSE(0));
508 return;
509 }
510
511 loc = info->location;
512
513 searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
514 p = strstr (msg->response_body->data, searchkey);
515 g_free (searchkey);
516 if (p) {
517 p += WEATHER_LOCATION_CODE_LEN4 + 11;
518 endtag = strstr (p, "</raw_text>");
519 if (endtag)
520 metar = g_strndup (p, endtag - p);
521 else
522 metar = g_strdup (p);
523 success = metar_parse (metar, info);
524 g_free (metar);
525 } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
526 /* The response doesn't even seem to have come from NOAA...
527 * most likely it is a wifi hotspot login page. Call that a
528 * network error.
529 */
530 info->network_error = TRUE(!(0));
531 }
532
533 info->valid = success;
534 request_done (info, TRUE(!(0)));
535}
536
537/* Read current conditions and fill in info structure */
538void
539metar_start_open (WeatherInfo *info)
540{
541 WeatherLocation *loc;
542 SoupMessage *msg;
543
544 g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
545 info->valid = info->network_error = FALSE(0);
546 loc = info->location;
547 if (loc == NULL((void*)0)) {
548 g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location")));
549 return;
550 }
551
552 msg = soup_form_request_new (
553 "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
554 "dataSource", "metars",
555 "requestType", "retrieve",
556 "format", "xml",
557 "hoursBeforeNow", "3",
558 "mostRecent", "true",
559 "fields", "raw_text",
560 "stationString", loc->code,
561 NULL((void*)0));
562 soup_session_queue_message (info->session, msg, metar_finish, info);
563
564 info->requests_pending++;
565}
diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/scanview.css b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2020-12-10-200341-5831-1@93dbf10c7ea2_master/sorttable.js b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2020-12-10-200341-5831-1@93dbf10c7ea2_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* location-entry.c - Location-selecting text entry
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+/**
+ * SECTION:location-entry
+ * @Title: MateWeatherLocationEntry
+ *
+ * A subclass of #GtkEntry that provides autocompletion on
+ * #MateWeatherLocation<!-- -->s
+ */
+
+G_DEFINE_TYPE (MateWeatherLocationEntry, mateweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+						 MateWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    MATEWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    MATEWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+static void     entry_changed (MateWeatherLocationEntry *entry);
+
+static void
+mateweather_location_entry_init (MateWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+
+    entry->custom_text = FALSE;
+    g_signal_connect (entry, "changed",
+		      G_CALLBACK (entry_changed), NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+    if (entry->top)
+	mateweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (mateweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+mateweather_location_entry_class_init (MateWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The MateWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected MateWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	mateweather_location_entry_build_model (MATEWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	mateweather_location_entry_set_location (MATEWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    MateWeatherLocationEntry *entry = MATEWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+entry_changed (MateWeatherLocationEntry *entry)
+{
+    entry->custom_text = TRUE;
+}
+
+static void
+set_location_internal (MateWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    MateWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	mateweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = mateweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	entry->custom_text = FALSE;
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+	entry->custom_text = TRUE;
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+/**
+ * mateweather_location_entry_set_location:
+ * @entry: a #MateWeatherLocationEntry
+ * @loc: (allow-none): a #MateWeatherLocation in @entry, or %NULL to
+ * clear @entry
+ *
+ * Sets @entry's location to @loc, and updates the text of the
+ * entry accordingly.
+ **/
+void
+mateweather_location_entry_set_location (MateWeatherLocationEntry *entry,
+				      MateWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+/**
+ * mateweather_location_entry_get_location:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Gets the location that was set by a previous call to
+ * mateweather_location_entry_set_location() or was selected by the user.
+ *
+ * Return value: (transfer full) (allow-none): the selected location
+ * (which you must unref when you are done with it), or %NULL if no
+ * location is selected.
+ **/
+MateWeatherLocation *
+mateweather_location_entry_get_location (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return mateweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+/**
+ * mateweather_location_entry_has_custom_text:
+ * @entry: a #MateWeatherLocationEntry
+ *
+ * Checks whether or not @entry's text has been modified by the user.
+ * Note that this does not mean that no location is associated with @entry.
+ * mateweather_location_entry_get_location() should be used for this.
+ *
+ * Return value: %TRUE if @entry's text was modified by the user, or %FALSE if
+ * it's set to the default text of a location.
+ **/
+gboolean
+mateweather_location_entry_has_custom_text (MateWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+
+    return entry->custom_text;
+}
+
+/**
+ * mateweather_location_entry_set_city:
+ * @entry: a #MateWeatherLocationEntry
+ * @city_name: (allow-none): the city name, or %NULL
+ * @code: the METAR station code
+ *
+ * Sets @entry's location to a city with the given @code, and given
+ * @city_name, if non-%NULL. If there is no matching city, sets
+ * @entry's location to %NULL.
+ *
+ * Return value: %TRUE if @entry's location could be set to a matching city,
+ * %FALSE otherwise.
+ **/
+gboolean
+mateweather_location_entry_set_city (MateWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    MateWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_val_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry), FALSE);
+    g_return_val_if_fail (code != NULL, FALSE);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = mateweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = mateweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return TRUE;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+
+    return FALSE;
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, MateWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    MateWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = mateweather_location_get_children (loc);
+
+    switch (mateweather_location_get_level (loc)) {
+    case MATEWEATHER_LOCATION_WORLD:
+    case MATEWEATHER_LOCATION_REGION:
+    case MATEWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       mateweather_location_get_name (loc),
+				       mateweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", mateweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", mateweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case MATEWEATHER_LOCATION_CITY:
+	if (children[0] && children[1]) {
+	    /* If there are multiple (<location>) children, add a line
+	     * for each of them.
+	     */
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_name (loc),
+						mateweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						mateweather_location_get_sort_name (loc),
+						mateweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	} else if (children[0]) {
+	    /* Else there's only one location. This is a mix of the
+	     * city-with-multiple-location case above and the
+	     * location-with-no-city case below.
+	     */
+	    display_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_name (loc),
+					    parent_display_name);
+	    compare_name = g_strdup_printf ("%s, %s",
+					    mateweather_location_get_sort_name (loc),
+					    parent_compare_name);
+
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, children[0],
+				MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				-1);
+
+	    g_free (display_name);
+	    g_free (compare_name);
+	}
+	break;
+
+    case MATEWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					mateweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    MATEWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    mateweather_location_free_children (loc, children);
+}
+
+static void
+mateweather_location_entry_build_model (MateWeatherLocationEntry *entry,
+				     MateWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    g_return_if_fail (MATEWEATHER_IS_LOCATION_ENTRY (entry));
+    entry->top = mateweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    MateWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			MATEWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			MATEWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+/**
+ * mateweather_location_entry_new:
+ * @top: the top-level location for the entry.
+ *
+ * Creates a new #MateWeatherLocationEntry.
+ *
+ * @top will normally be a location returned from
+ * mateweather_location_new_world(), but you can create an entry that
+ * only accepts a smaller set of locations if you want.
+ *
+ * Return value: the new #MateWeatherLocationEntry
+ **/
+GtkWidget *
+mateweather_location_entry_new (MateWeatherLocation *top)
+{
+    return g_object_new (MATEWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/1.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/1.html new file mode 100644 index 0000000..cc8f781 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/1.html @@ -0,0 +1,994 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* mateweather-timezone.c - Timezone handling
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "mateweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+/**
+ * SECTION:mateweather-timezone
+ * @Title: MateWeatherTimezone
+ *
+ * A timezone.
+ *
+ * There are no public methods for creating timezones; they can only
+ * be created by calling mateweather_location_new_world() to parse
+ * Locations.xml, and then calling various #MateWeatherLocation methods
+ * to extract relevant timezones from the location hierarchy.
+ */
+struct _MateWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static MateWeatherTimezone *
+parse_timezone (MateWeatherParser *parser)
+{
+    MateWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset = 0, dst_offset = 0;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = mateweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (MateWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+MateWeatherTimezone **
+mateweather_timezones_parse_xml (MateWeatherParser *parser)
+{
+    GPtrArray *zones;
+    MateWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (zone)
+		g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (MateWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	mateweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+/**
+ * mateweather_timezone_ref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Adds 1 to @zone's reference count.
+ *
+ * Return value: @zone
+ **/
+MateWeatherTimezone *
+mateweather_timezone_ref (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+
+    zone->ref_count++;
+    return zone;
+}
+
+/**
+ * mateweather_timezone_unref:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
+ **/
+void
+mateweather_timezone_unref (MateWeatherTimezone *zone)
+{
+    g_return_if_fail (zone != NULL);
+
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (MateWeatherTimezone, zone);
+    }
+}
+
+GType
+mateweather_timezone_get_type (void)
+{
+    static volatile gsize type_volatile = 0;
+
+    if (g_once_init_enter (&type_volatile)) {
+	GType type = g_boxed_type_register_static (
+	    g_intern_static_string ("MateWeatherTimezone"),
+	    (GBoxedCopyFunc) mateweather_timezone_ref,
+	    (GBoxedFreeFunc) mateweather_timezone_unref);
+	g_once_init_leave (&type_volatile, type);
+    }
+    return type_volatile;
+}
+
+/**
+ * mateweather_timezone_get_utc:
+ *
+ * Gets the UTC timezone.
+ *
+ * Return value: a #MateWeatherTimezone for UTC, or %NULL on error.
+ **/
+MateWeatherTimezone *
+mateweather_timezone_get_utc (void)
+{
+    MateWeatherTimezone *zone = NULL;
+
+    zone = g_slice_new0 (MateWeatherTimezone);
+    zone->ref_count = 1;
+    zone->id = g_strdup ("GMT");
+    zone->name = g_strdup (_("Greenwich Mean Time"));
+    zone->offset = 0;
+    zone->has_dst = FALSE;
+    zone->dst_offset = 0;
+
+    return zone;
+}
+
+/**
+ * mateweather_timezone_get_name:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's name; a translated, user-presentable string.
+ *
+ * Note that the returned name might not be unique among timezones,
+ * and may not make sense to the user unless it is presented along
+ * with the timezone's country's name (or in some context where the
+ * country is obvious).
+ *
+ * Return value: @zone's name
+ **/
+const char *
+mateweather_timezone_get_name (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->name;
+}
+
+/**
+ * mateweather_timezone_get_tzid:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's tzdata identifier, eg "America/New_York".
+ *
+ * Return value: @zone's tzid
+ **/
+const char *
+mateweather_timezone_get_tzid (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, NULL);
+    return zone->id;
+}
+
+/**
+ * mateweather_timezone_get_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
+ * %120 would indicate "GMT+2".
+ *
+ * Return value: @zone's standard offset, in minutes
+ **/
+int
+mateweather_timezone_get_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    return zone->offset;
+}
+
+/**
+ * mateweather_timezone_has_dst:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Checks if @zone observes daylight/summer time for part of the year.
+ *
+ * Return value: %TRUE if @zone observes daylight/summer time.
+ **/
+gboolean
+mateweather_timezone_has_dst (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, FALSE);
+    return zone->has_dst;
+}
+
+/**
+ * mateweather_timezone_get_dst_offset:
+ * @zone: a #MateWeatherTimezone
+ *
+ * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
+ * a value of %120 would indicate "GMT+2". This is only meaningful if
+ * mateweather_timezone_has_dst() returns %TRUE.
+ *
+ * Return value: @zone's daylight/summer time offset, in minutes
+ **/
+int
+mateweather_timezone_get_dst_offset (MateWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone != NULL, 0);
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/10.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/10.html new file mode 100644 index 0000000..3523ae6 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/10.html @@ -0,0 +1,384 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-wx.c - Weather server functions (WX Radar)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+wx_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    GdkPixbufAnimation *animation;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get radar map image: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+	g_object_unref (info->radar_loader);
+	request_done (info, FALSE);
+	return;
+    }
+
+    gdk_pixbuf_loader_close (info->radar_loader, NULL);
+    animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+    if (animation != NULL) {
+	if (info->radar)
+	    g_object_unref (info->radar);
+	info->radar = animation;
+	g_object_ref (info->radar);
+    }
+    g_object_unref (info->radar_loader);
+
+    request_done (info, TRUE);
+}
+
+static void
+wx_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;<--- Assignment 'info=(struct _WeatherInfo*)data', assigned value is 0
+    GError *error = NULL;
+
+    g_return_if_fail (info != NULL);<--- Assuming that condition 'info!=NULL' is not redundant
+
+    gdk_pixbuf_loader_write (info->radar_loader, (guchar *)chunk->data,<--- Null pointer dereference
+			     chunk->length, &error);
+    if (error) {
+	g_print ("%s \n", error->message);
+	g_error_free (error);
+    }
+}
+
+/* Get radar map and into newly allocated pixmap */
+void
+wx_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    g_return_if_fail (info != NULL);
+    info->radar = NULL;
+    info->radar_loader = gdk_pixbuf_loader_new ();
+    loc = info->location;
+    g_return_if_fail (loc != NULL);
+
+    if (info->radar_url)
+	url = g_strdup (info->radar_url);
+    else {
+	if (loc->radar[0] == '-')
+	    return;
+	url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+    }
+
+    msg = soup_message_new ("GET", url);
+    if (!msg) {
+	g_warning ("Invalid radar URL: %s\n", url);
+	g_free (url);
+	return;
+    }
+
+    g_signal_connect (msg, "got-chunk", G_CALLBACK (wx_got_chunk), info);
+    soup_message_body_set_accumulate (msg->response_body, FALSE);
+    soup_session_queue_message (info->session, msg, wx_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/11.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/11.html new file mode 100644 index 0000000..a3b1f23 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/11.html @@ -0,0 +1,3562 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather.c - Overall weather server functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fenv.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#include <time.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+#define MOON_PHASES 36
+
+/**
+ * SECTION:weather
+ * @Title: weather
+ */
+
+static void _weather_internal_check (void);
+
+
+static inline void
+mateweather_gettext_init (void)
+{
+    static gsize mateweather_gettext_initialized = FALSE;
+
+    if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))) {
+        bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+        g_once_init_leave (&mateweather_gettext_initialized, TRUE);
+    }
+}
+
+const char *
+mateweather_gettext (const char *str)
+{
+    mateweather_gettext_init ();
+    return dgettext (GETTEXT_PACKAGE, str);
+}
+
+const char *
+mateweather_dpgettext (const char *context,
+                    const char *str)
+{
+    mateweather_gettext_init ();
+    return g_dpgettext2 (GETTEXT_PACKAGE, context, str);
+}
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble
+dmsh2rad (const gchar *latlon)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+    gdouble value;
+
+    if (latlon == NULL)
+	return DBL_MAX;
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon) {
+        return DBL_MAX;
+    } else if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else if (p2 == 1 + p1) {
+	return DBL_MAX;
+    } else {
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    }
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return DBL_MAX;
+    value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	value = -value;
+    else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+	value = DBL_MAX;
+    return value;
+}
+
+WeatherLocation *
+weather_location_new (const gchar *name, const gchar *code,
+		      const gchar *zone, const gchar *radar,
+		      const gchar *coordinates,
+		      const gchar *country_code,
+		      const gchar *tz_hint)
+{
+    WeatherLocation *location;
+
+    _weather_internal_check ();
+
+    location = g_new (WeatherLocation, 1);
+
+    /* name and metar code must be set */
+    location->name = g_strdup (name);
+    location->code = g_strdup (code);
+
+    if (zone) {
+        location->zone = g_strdup (zone);
+    } else {
+        location->zone = g_strdup ("------");
+    }
+
+    if (radar) {
+        location->radar = g_strdup (radar);
+    } else {
+        location->radar = g_strdup ("---");
+    }
+
+    if (location->zone[0] == '-') {
+        location->zone_valid = FALSE;
+    } else {
+        location->zone_valid = TRUE;
+    }
+
+    location->coordinates = NULL;
+    if (coordinates)
+    {
+	char **pieces;
+
+	pieces = g_strsplit (coordinates, " ", -1);
+
+	if (g_strv_length (pieces) == 2)
+	{
+            location->coordinates = g_strdup (coordinates);
+            location->latitude = dmsh2rad (pieces[0]);
+	    location->longitude = dmsh2rad (pieces[1]);
+	}
+
+	g_strfreev (pieces);
+    }
+
+    if (!location->coordinates)
+    {
+        location->coordinates = g_strdup ("---");
+        location->latitude = DBL_MAX;
+        location->longitude = DBL_MAX;
+    }
+
+    location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+    location->country_code = g_strdup (country_code);
+    location->tz_hint = g_strdup (tz_hint);
+
+    return location;
+}
+
+WeatherLocation *
+weather_location_clone (const WeatherLocation *location)
+{
+    WeatherLocation *clone;
+
+    g_return_val_if_fail (location != NULL, NULL);
+
+    clone = weather_location_new (location->name,
+				  location->code, location->zone,
+				  location->radar, location->coordinates,
+				  location->country_code, location->tz_hint);
+    clone->latitude = location->latitude;
+    clone->longitude = location->longitude;
+    clone->latlon_valid = location->latlon_valid;
+    return clone;
+}
+
+void
+weather_location_free (WeatherLocation *location)
+{
+    if (location) {
+        g_free (location->name);
+        g_free (location->code);
+        g_free (location->zone);
+        g_free (location->radar);
+        g_free (location->coordinates);
+        g_free (location->country_code);
+        g_free (location->tz_hint);
+
+        g_free (location);
+    }
+}
+
+gboolean
+weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+    /* if something is NULL, then it's TRUE if and only if both are NULL) */
+    if (location1 == NULL || location2 == NULL)
+        return (location1 == location2);
+    if (!location1->code || !location2->code)
+        return (location1->code == location2->code);
+    if (!location1->name || !location2->name)
+        return (location1->name == location2->name);
+
+    return ((strcmp (location1->code, location2->code) == 0) &&
+	    (strcmp (location1->name, location2->name) == 0));
+}
+
+static const gchar *wind_direction_str[] = {
+    N_("Variable"),
+    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *
+weather_wind_direction_string (WeatherWindDirection wind)
+{
+    if (wind <= WIND_INVALID || wind >= WIND_LAST)
+	return _("Invalid");
+
+    return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+    N_("Clear Sky"),
+    N_("Broken clouds"),
+    N_("Scattered clouds"),
+    N_("Few clouds"),
+    N_("Overcast")
+};
+
+const gchar *
+weather_sky_string (WeatherSky sky)
+{
+    if (sky <= SKY_INVALID || sky >= SKY_LAST)
+	return _("Invalid");
+
+    return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/*                   NONE                         VICINITY                             LIGHT                      MODERATE                      HEAVY                      SHALLOW                      PATCHES                         PARTIAL                      THUNDERSTORM                    BLOWING                      SHOWERS                         DRIFTING                      FREEZING                      */
+/*               *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* Translators: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.php */
+    /* NONE          */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        "??",                           "??",                         "??"                         },
+    /* DRIZZLE       */ {N_("Drizzle"),               "??",                                N_("Light drizzle"),       N_("Moderate drizzle"),       N_("Heavy drizzle"),       "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         N_("Freezing drizzle")       },
+    /* RAIN          */ {N_("Rain"),                  "??",                                N_("Light rain"),          N_("Moderate rain"),          N_("Heavy rain"),          "??",                        "??",                           "??",                        N_("Thunderstorm"),             "??",                        N_("Rain showers"),             "??",                         N_("Freezing rain")          },
+    /* SNOW          */ {N_("Snow"),                  "??",                                N_("Light snow"),          N_("Moderate snow"),          N_("Heavy snow"),          "??",                        "??",                           "??",                        N_("Snowstorm"),                N_("Blowing snowfall"),      N_("Snow showers"),             N_("Drifting snow"),          "??"                         },
+    /* SNOW_GRAINS   */ {N_("Snow grains"),           "??",                                N_("Light snow grains"),   N_("Moderate snow grains"),   N_("Heavy snow grains"),   "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_CRYSTALS  */ {N_("Ice crystals"),          "??",                                "??",                      N_("Ice crystals"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* ICE_PELLETS   */ {N_("Ice pellets"),           "??",                                N_("Few ice pellets"),     N_("Moderate ice pellets"),   N_("Heavy ice pellets"),   "??",                        "??",                           "??",                        N_("Ice pellet storm"),         "??",                        N_("Showers of ice pellets"),   "??",                         "??"                         },
+    /* HAIL          */ {N_("Hail"),                  "??",                                "??",                      N_("Hail"),                   "??",                      "??",                        "??",                           "??",                        N_("Hailstorm"),                "??",                        N_("Hail showers"),             "??",                         "??",                        },
+    /* SMALL_HAIL    */ {N_("Small hail"),            "??",                                "??",                      N_("Small hail"),             "??",                      "??",                        "??",                           "??",                        N_("Small hailstorm"),          "??",                        N_("Showers of small hail"),    "??",                         "??"                         },
+    /* PRECIPITATION */ {N_("Unknown precipitation"), "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* MIST          */ {N_("Mist"),                  "??",                                "??",                      N_("Mist"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FOG           */ {N_("Fog"),                   N_("Fog in the vicinity") ,          "??",                      N_("Fog"),                    "??",                      N_("Shallow fog"),           N_("Patches of fog"),           N_("Partial fog"),           "??",                           "??",                        "??",                           "??",                         N_("Freezing fog")           },
+    /* SMOKE         */ {N_("Smoke"),                 "??",                                "??",                      N_("Smoke"),                  "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* VOLCANIC_ASH  */ {N_("Volcanic ash"),          "??",                                "??",                      N_("Volcanic ash"),           "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SAND          */ {N_("Sand"),                  "??",                                "??",                      N_("Sand"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sand"),          "",                             N_("Drifting sand"),          "??"                         },
+    /* HAZE          */ {N_("Haze"),                  "??",                                "??",                      N_("Haze"),                   "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SPRAY         */ {"??",                        "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing sprays"),        "??",                           "??",                         "??"                         },
+    /* DUST          */ {N_("Dust"),                  "??",                                "??",                      N_("Dust"),                   "??",                      "??",                        "??",                           "??",                        "??",                           N_("Blowing dust"),          "??",                           N_("Drifting dust"),          "??"                         },
+    /* SQUALL        */ {N_("Squall"),                "??",                                "??",                      N_("Squall"),                 "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* SANDSTORM     */ {N_("Sandstorm"),             N_("Sandstorm in the vicinity") ,    "??",                      N_("Sandstorm"),              N_("Heavy sandstorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUSTSTORM     */ {N_("Duststorm"),             N_("Duststorm in the vicinity") ,    "??",                      N_("Duststorm"),              N_("Heavy duststorm"),     "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* FUNNEL_CLOUD  */ {N_("Funnel cloud"),          "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* TORNADO       */ {N_("Tornado"),               "??",                                "??",                      "??",                         "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         },
+    /* DUST_WHIRLS   */ {N_("Dust whirls"),           N_("Dust whirls in the vicinity") ,  "??",                      N_("Dust whirls"),            "??",                      "??",                        "??",                           "??",                        "??",                           "??",                        "??",                           "??",                         "??"                         }
+};
+
+const gchar *
+weather_conditions_string (WeatherConditions cond)
+{
+    const gchar *str;
+
+    if (!cond.significant) {
+	return "-";
+    } else {
+	if (cond.phenomenon > PHENOMENON_INVALID &&
+	    cond.phenomenon < PHENOMENON_LAST &&
+	    cond.qualifier > QUALIFIER_INVALID &&
+	    cond.qualifier < QUALIFIER_LAST)
+	    str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+	else
+	    str = _("Invalid");
+	return (strlen (str) > 0) ? str : "-";
+    }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean
+requests_init (WeatherInfo *info)
+{
+    if (info->requests_pending)
+        return FALSE;
+
+    return TRUE;
+}
+
+void request_done (WeatherInfo *info, gboolean ok)
+{
+    if (ok) {
+	(void) calc_sun (info);
+	info->moonValid = info->valid && calc_moon (info);
+    }
+    if (!--info->requests_pending)
+        info->finish_cb (info, info->cb_data);
+}
+
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+static inline gdouble
+calc_humidity (gdouble temp, gdouble dewp)
+{
+    gdouble esat, esurf;
+
+    if (temp > -500.0 && dewp > -500.0) {
+	temp = TEMP_F_TO_C (temp);
+	dewp = TEMP_F_TO_C (dewp);
+
+	esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp));
+	esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp));
+    } else {
+	esurf = -1.0;
+	esat = 1.0;
+    }
+    return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble
+calc_apparent (WeatherInfo *info)
+{
+    gdouble temp = info->temp;
+    gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed);
+    gdouble apparent = -1000.;
+
+    /*
+     * Wind chill calculations as of 01-Nov-2001
+     * http://www.nws.noaa.gov/om/windchill/index.shtml
+     * Some pages suggest that the formula will soon be adjusted
+     * to account for solar radiation (bright sun vs cloudy sky)
+     */
+    if (temp <= 50.0) {
+        if (wind > 3.0) {
+	    gdouble v = pow (wind, 0.16);
+	    apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+	} else if (wind >= 0.) {
+	    apparent = temp;
+	}
+    }
+    /*
+     * Heat index calculations:
+     * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+     */
+    else if (temp >= 80.0) {
+        if (info->temp >= -500. && info->dew >= -500.) {
+	    gdouble humidity = calc_humidity (info->temp, info->dew);
+	    gdouble t2 = temp * temp;
+	    gdouble h2 = humidity * humidity;
+
+#if 1
+	    /*
+	     * A really precise formula.  Note that overall precision is
+	     * constrained by the accuracy of the instruments and that the
+	     * we receive the temperature and dewpoints as integers.
+	     */
+	    gdouble t3 = t2 * temp;
+	    gdouble h3 = h2 * temp;
+
+	    apparent = 16.923
+		+ 0.185212 * temp
+		+ 5.37941 * humidity
+		- 0.100254 * temp * humidity
+		+ 9.41695e-3 * t2
+		+ 7.28898e-3 * h2
+		+ 3.45372e-4 * t2 * humidity
+		- 8.14971e-4 * temp * h2
+		+ 1.02102e-5 * t2 * h2
+		- 3.8646e-5 * t3
+		+ 2.91583e-5 * h3
+		+ 1.42721e-6 * t3 * humidity
+		+ 1.97483e-7 * temp * h3
+		- 2.18429e-8 * t3 * h2
+		+ 8.43296e-10 * t2 * h3
+		- 4.81975e-11 * t3 * h3;
+#else
+	    /*
+	     * An often cited alternative: values are within 5 degrees for
+	     * most ranges between 10% and 70% humidity and to 110 degrees.
+	     */
+	    apparent = - 42.379
+		+  2.04901523 * temp
+		+ 10.14333127 * humidity
+		-  0.22475541 * temp * humidity
+		-  6.83783e-3 * t2
+		-  5.481717e-2 * h2
+		+  1.22874e-3 * t2 * humidity
+		+  8.5282e-4 * temp * h2
+		-  1.99e-6 * t2 * h2;
+#endif
+	}
+    } else {
+        apparent = temp;
+    }
+
+    return apparent;
+}
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+		    WeatherLocation *location,
+		    const WeatherPrefs *prefs,
+		    WeatherInfoFunc cb,
+		    gpointer data)
+{
+    g_return_val_if_fail (((info == NULL) && (location != NULL)) || \
+			  ((info != NULL) && (location == NULL)), NULL);
+    g_return_val_if_fail (prefs != NULL, NULL);
+
+    /* FIXME: i'm not sure this works as intended anymore */
+    if (!info) {
+    	info = g_new0 (WeatherInfo, 1);
+    	info->requests_pending = 0;
+    	info->location = weather_location_clone (location);
+    } else {
+        location = info->location;<--- Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?<--- Variable 'location' is assigned a value that is never used.
+	if (info->forecast)
+	    g_free (info->forecast);
+	info->forecast = NULL;
+
+	free_forecast_list (info);
+
+	if (info->radar != NULL) {
+	    g_object_unref (info->radar);
+	    info->radar = NULL;
+	}
+    }
+
+    /* Update in progress */
+    if (!requests_init (info)) {
+        return NULL;
+    }
+
+    /* Defaults (just in case...) */
+    /* Well, no just in case anymore.  We may actually fail to fetch some
+     * fields. */
+    info->forecast_type = prefs->type;
+
+    info->temperature_unit = prefs->temperature_unit;
+    info->speed_unit = prefs->speed_unit;
+    info->pressure_unit = prefs->pressure_unit;
+    info->distance_unit = prefs->distance_unit;
+
+    info->update = 0;
+    info->sky = -1;
+    info->cond.significant = FALSE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
+    info->dew = -1000.0;
+    info->wind = -1;
+    info->windspeed = -1;
+    info->pressure = -1.0;
+    info->visibility = -1.0;
+    info->sunriseValid = FALSE;
+    info->sunsetValid = FALSE;
+    info->moonValid = FALSE;
+    info->sunrise = 0;
+    info->sunset = 0;
+    info->moonphase = 0;
+    info->moonlatitude = 0;
+    info->forecast = NULL;
+    info->forecast_list = NULL;
+    info->radar = NULL;
+    info->radar_url = prefs->radar && prefs->radar_custom_url ?
+    		      g_strdup (prefs->radar_custom_url) : NULL;
+    info->finish_cb = cb;
+    info->cb_data = data;
+
+    if (!info->session) {
+	info->session = soup_session_async_new ();
+	soup_session_add_feature_by_type (info->session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+    }
+
+    metar_start_open (info);
+    iwin_start_open (info);
+
+    if (prefs->radar) {
+        wx_start_open (info);
+    }
+
+    return info;
+}
+
+void
+weather_info_abort (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    if (info->session) {
+	soup_session_abort (info->session);
+	info->requests_pending = 0;
+    }
+}
+
+WeatherInfo *
+weather_info_clone (const WeatherInfo *info)
+{
+    WeatherInfo *clone;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    clone = g_new (WeatherInfo, 1);
+
+
+    /* move everything */
+    memmove (clone, info, sizeof (WeatherInfo));
+
+
+    /* special moves */
+    clone->location = weather_location_clone (info->location);
+    /* This handles null correctly */
+    clone->forecast = g_strdup (info->forecast);
+    clone->radar_url = g_strdup (info->radar_url);
+
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
+    clone->radar = info->radar;
+    if (clone->radar != NULL)
+	g_object_ref (clone->radar);
+
+    return clone;
+}
+
+void
+weather_info_free (WeatherInfo *info)
+{
+    if (!info)
+        return;
+
+    weather_info_abort (info);
+    if (info->session)
+	g_object_unref (info->session);
+
+    weather_location_free (info->location);
+    info->location = NULL;
+
+    g_free (info->forecast);
+    info->forecast = NULL;
+
+    free_forecast_list (info);
+
+    if (info->radar != NULL) {
+        g_object_unref (info->radar);
+        info->radar = NULL;
+    }
+
+    g_free (info);
+}
+
+gboolean
+weather_info_is_valid (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->valid;
+}
+
+gboolean
+weather_info_network_error (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    return info->network_error;
+}
+
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail (info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
+const WeatherLocation *
+weather_info_get_location (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->location;
+}
+
+const gchar *
+weather_info_get_location_name (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    g_return_val_if_fail (info->location != NULL, NULL);
+    return info->location->name;
+}
+
+const gchar *
+weather_info_get_update (WeatherInfo *info)
+{
+    static gchar buf[200];
+    char *utf8, *timeformat;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    if (info->update != 0) {
+        struct tm tm;
+        localtime_r (&info->update, &tm);
+	/* Translators: this is a format string for strftime
+	 *             see `man 3 strftime` for more details
+	 */
+	timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+					 NULL, NULL, NULL);
+	if (!timeformat) {
+	    strcpy (buf, "???");
+	}
+	else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {<--- Unsigned less than zero
+	    strcpy (buf, "???");
+	}
+	g_free (timeformat);
+
+	/* Convert to UTF-8 */
+	utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+	strcpy (buf, utf8);
+	g_free (utf8);
+    } else {
+        strncpy (buf, _("Unknown observation time"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sky (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    if (info->sky < 0)
+	return _("Unknown");
+    return weather_sky_string (info->sky);
+}
+
+const gchar *
+weather_info_get_conditions (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+    return weather_conditions_string (info->cond);
+}
+
+static const gchar *
+temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case TEMP_UNIT_FAHRENHEIT:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260F"), temp);
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (temp);
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260F"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_CENTIGRADE:
+	if (!want_round) {
+	    /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	    g_snprintf (buf, sizeof (buf), _("%.1f \302\260C"), TEMP_F_TO_C (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_C (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
+	        g_snprintf (buf, sizeof (buf), _("%d \302\260C"), (int)temp_r);
+	}
+	break;
+    case TEMP_UNIT_KELVIN:
+	if (!want_round) {
+	    /* Translators: This is the temperature in kelvin */
+	    g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K (temp));
+	} else {
+	    const int range_problem = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+	    gdouble temp_r;
+
+	    feclearexcept(range_problem);
+	    temp_r = round (TEMP_F_TO_K (temp));
+	    if (fetestexcept(range_problem))
+	        g_snprintf (buf, sizeof (buf), _("n/a"));
+	    else
+	        /* Translators: This is the temperature in kelvin */
+	        g_snprintf (buf, sizeof (buf), _("%d K"), (int)temp_r);
+	}
+	break;
+
+    case TEMP_UNIT_INVALID:
+    case TEMP_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal temperature unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_temp (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->temp < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_dew (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->dew < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_humidity (WeatherInfo *info)
+{
+    static gchar buf[20];
+    gdouble humidity;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+
+    humidity = calc_humidity (info->temp, info->dew);
+    if (humidity < 0.0)
+        return _("Unknown");
+
+    /* Translators: This is the humidity in percent */
+    g_snprintf (buf, sizeof (buf), _("%.f%%"), humidity);
+    return buf;
+}
+
+const gchar *
+weather_info_get_apparent (WeatherInfo *info)
+{
+    gdouble apparent;
+
+    g_return_val_if_fail (info != NULL, NULL);
+    if (!info->valid)
+        return "-";
+
+    apparent = calc_apparent (info);
+    if (apparent < -500.0)
+        return _("Unknown");
+
+    return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *
+windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+    static gchar buf[100];
+
+    switch (to_unit) {
+    case SPEED_UNIT_KNOTS:
+	/* Translators: This is the wind speed in knots */
+	g_snprintf (buf, sizeof (buf), _("%0.1f knots"), knots);
+	break;
+    case SPEED_UNIT_MPH:
+	/* Translators: This is the wind speed in miles per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH (knots));
+	break;
+    case SPEED_UNIT_KPH:
+	/* Translators: This is the wind speed in kilometers per hour */
+	g_snprintf (buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH (knots));
+	break;
+    case SPEED_UNIT_MS:
+	/* Translators: This is the wind speed in meters per second */
+	g_snprintf (buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS (knots));
+	break;
+    case SPEED_UNIT_BFT:
+	/* Translators: This is the wind speed as a Beaufort force factor
+	 * (commonly used in nautical wind estimation).
+	 */
+	g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+		    WINDSPEED_KNOTS_TO_BFT (knots));
+	break;
+    case SPEED_UNIT_INVALID:
+    case SPEED_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal speed unit: %d", to_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_wind (WeatherInfo *info)
+{
+    static gchar buf[200];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->windspeed < 0.0 || info->wind < 0)
+        return _("Unknown");
+    if (info->windspeed == 0.00) {
+        strncpy (buf, _("Calm"), sizeof (buf));
+	buf[sizeof (buf)-1] = '\0';
+    } else {
+        /* Translators: This is 'wind direction' / 'wind speed' */
+        g_snprintf (buf, sizeof (buf), _("%s / %s"),
+		    weather_wind_direction_string (info->wind),
+		    windspeed_string (info->windspeed, info->speed_unit));
+    }
+    return buf;
+}
+
+const gchar *
+weather_info_get_pressure (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->pressure < 0.0)
+        return _("Unknown");
+
+    switch (info->pressure_unit) {
+    case PRESSURE_UNIT_INCH_HG:
+	/* Translators: This is pressure in inches of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+	break;
+    case PRESSURE_UNIT_MM_HG:
+	/* Translators: This is pressure in millimeters of mercury */
+	g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM (info->pressure));
+	break;
+    case PRESSURE_UNIT_KPA:
+	/* Translators: This is pressure in kiloPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_HPA:
+	/* Translators: This is pressure in hectoPascals */
+	g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA (info->pressure));
+	break;
+    case PRESSURE_UNIT_MB:
+	/* Translators: This is pressure in millibars */
+	g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB (info->pressure));
+	break;
+    case PRESSURE_UNIT_ATM:
+	/* Translators: This is pressure in atmospheres */
+	g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM (info->pressure));
+	break;
+
+    case PRESSURE_UNIT_INVALID:
+    case PRESSURE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_visibility (WeatherInfo *info)
+{
+    static gchar buf[100];
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return "-";
+    if (info->visibility < 0.0)
+        return _("Unknown");
+
+    switch (info->distance_unit) {
+    case DISTANCE_UNIT_MILES:
+	/* Translators: This is the visibility in miles */
+	g_snprintf (buf, sizeof (buf), _("%.1f miles"), info->visibility);
+	break;
+    case DISTANCE_UNIT_KM:
+	/* Translators: This is the visibility in kilometers */
+	g_snprintf (buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM (info->visibility));
+	break;
+    case DISTANCE_UNIT_METERS:
+	/* Translators: This is the visibility in meters */
+	g_snprintf (buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M (info->visibility));
+	break;
+
+    case DISTANCE_UNIT_INVALID:
+    case DISTANCE_UNIT_DEFAULT:
+    default:
+	g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
+	return _("Unknown");
+    }
+
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunrise (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunrise, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_sunset (WeatherInfo *info)
+{
+    static gchar buf[200];
+    struct tm tm;
+
+    g_return_val_if_fail (info && info->location, NULL);
+
+    if (!info->location->latlon_valid)
+        return "-";
+    if (!info->valid)
+        return "-";
+    if (!calc_sun (info))
+        return "-";
+
+    localtime_r (&info->sunset, &tm);
+    if (strftime (buf, sizeof (buf), _("%H:%M"), &tm) <= 0)<--- Unsigned less than zero
+        return "-";
+    return buf;
+}
+
+const gchar *
+weather_info_get_forecast (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->forecast;
+}
+
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
+GdkPixbufAnimation *
+weather_info_get_radar (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+    return info->radar;
+}
+
+const gchar *
+weather_info_get_temp_summary (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || info->temp < -500.0)
+        return "--";
+
+    return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *
+weather_info_get_weather_summary (WeatherInfo *info)
+{
+    const gchar *buf;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return g_strdup (_("Retrieval failed"));
+    buf = weather_info_get_conditions (info);
+    if (!strcmp (buf, "-"))
+        buf = weather_info_get_sky (info);
+    return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+    WeatherConditions cond;
+    WeatherSky        sky;
+    time_t            current_time;
+    gboolean          daytime;
+    gchar*            icon;
+    static gchar      icon_buffer[32];
+    WeatherMoonPhase  moonPhase;
+    WeatherMoonLatitude moonLat;
+    gint              phase;
+
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+        return NULL;
+
+    cond = info->cond;
+    sky = info->sky;
+
+    if (cond.significant) {
+	if (cond.phenomenon != PHENOMENON_NONE &&
+	    cond.qualifier == QUALIFIER_THUNDERSTORM)
+            return "weather-storm";
+
+        switch (cond.phenomenon) {
+	case PHENOMENON_INVALID:
+	case PHENOMENON_LAST:
+	case PHENOMENON_NONE:
+	    break;
+
+	case PHENOMENON_DRIZZLE:
+	case PHENOMENON_RAIN:
+	case PHENOMENON_UNKNOWN_PRECIPITATION:
+	case PHENOMENON_HAIL:
+	case PHENOMENON_SMALL_HAIL:
+	    return "weather-showers";
+
+	case PHENOMENON_SNOW:
+	case PHENOMENON_SNOW_GRAINS:
+	case PHENOMENON_ICE_PELLETS:
+	case PHENOMENON_ICE_CRYSTALS:
+	    return "weather-snow";
+
+	case PHENOMENON_TORNADO:
+	case PHENOMENON_SQUALL:
+	    return "weather-storm";
+
+	case PHENOMENON_MIST:
+	case PHENOMENON_FOG:
+	case PHENOMENON_SMOKE:
+	case PHENOMENON_VOLCANIC_ASH:
+	case PHENOMENON_SAND:
+	case PHENOMENON_HAZE:
+	case PHENOMENON_SPRAY:
+	case PHENOMENON_DUST:
+	case PHENOMENON_SANDSTORM:
+	case PHENOMENON_DUSTSTORM:
+	case PHENOMENON_FUNNEL_CLOUD:
+	case PHENOMENON_DUST_WHIRLS:
+	    return "weather-fog";
+        }
+    }
+
+    if (info->midnightSun ||
+	(!info->sunriseValid && !info->sunsetValid))
+	daytime = TRUE;
+    else if (info->polarNight)
+	daytime = FALSE;
+    else {
+	current_time = time (NULL);
+	daytime =
+	    ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
+	    ( !info->sunsetValid || (current_time < info->sunset) );
+    }
+
+    switch (sky) {
+    case SKY_INVALID:
+    case SKY_LAST:
+    case SKY_CLEAR:
+	if (daytime)
+	    return "weather-clear";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-clear-night");
+	    break;
+	}
+
+    case SKY_BROKEN:
+    case SKY_SCATTERED:
+    case SKY_FEW:
+	if (daytime)
+	    return "weather-few-clouds";
+	else {
+	    icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
+	    break;
+	}
+
+    case SKY_OVERCAST:
+	return "weather-overcast";
+
+    default: /* unrecognized */
+	return NULL;
+    }
+
+    /*
+     * A phase-of-moon icon is to be returned.
+     * Determine which one based on the moon's location
+     */
+    if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
+	phase = (gint)((moonPhase * MOON_PHASES / 360.) + 0.5);
+	if (phase == MOON_PHASES) {
+	    phase = 0;
+	} else if (phase > 0 &&
+		   (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)
+		    < moonLat)) {
+	    /*
+	     * Locations south of the moon's latitude will see the moon in the
+	     * northern sky.  The moon waxes and wanes from left to right
+	     * so we reference an icon running in the opposite direction.
+	     */
+	    phase = MOON_PHASES - phase;
+	}
+
+	/*
+	 * If the moon is not full then append the angle to the icon string.
+	 * Note that an icon by this name is not required to exist:
+	 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
+	 * the full moon image.
+	 */
+	if ((0 == (MOON_PHASES & 0x1)) && (MOON_PHASES/2 != phase)) {
+	    g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
+		       "-%03d", phase * 360 / MOON_PHASES);
+	}
+    }
+    return icon_buffer;
+}
+
+static gboolean
+temperature_value (gdouble temp_f,
+		   TempUnit to_unit,
+		   gdouble *value,
+		   TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (temp_f < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = temp_f;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (temp_f);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (temp_f);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
+	  info->cond.phenomenon < PHENOMENON_LAST &&
+	  info->cond.qualifier > QUALIFIER_INVALID &&
+	  info->cond.qualifier < QUALIFIER_LAST))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunriseValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunsetValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_moonphase (WeatherInfo      *info,
+				  WeatherMoonPhase *value,
+				  WeatherMoonLatitude *lat)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->moonValid)
+	return FALSE;
+
+    *value = info->moonphase;
+    *lat   = info->moonlatitude;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}
+
+/**
+ * weather_info_get_upcoming_moonphases:
+ * @info:   WeatherInfo containing the time_t of interest
+ * @phases: An array of four time_t values that will hold the returned values.
+ *    The values are estimates of the time of the next new, quarter, full and
+ *    three-quarter moons.
+ *
+ * Returns: gboolean indicating success or failure
+ */
+gboolean
+weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phases != NULL, FALSE);
+
+    return calc_moon_phases(info, phases);
+}
+
+static void
+_weather_internal_check (void)
+{
+    g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST);
+    g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST);
+    g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST);
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/2.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/2.html new file mode 100644 index 0000000..f232863 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/2.html @@ -0,0 +1,708 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* parser.c - Locations.xml parser
+ *
+ * Copyright 2008, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * mateweather_parser_get_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_value (MateWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * mateweather_parser_get_localized_value:
+ * @parser: a #MateWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+mateweather_parser_get_localized_value (MateWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+MateWeatherParser *
+mateweather_parser_new (gboolean use_regions)
+{
+    MateWeatherParser *parser;
+    int zlib_support;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (MateWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    zlib_support = xmlHasFeature (XML_WITH_ZLIB);
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+
+        if (!zlib_support)
+            continue;
+
+	filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
+				    MATEWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
+
+    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
+        g_free (filename);
+	filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
+    }
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "mateweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    mateweather_parser_free (parser);
+    return NULL;
+}
+
+void
+mateweather_parser_free (MateWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (MateWeatherParser, parser);
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/3.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/3.html new file mode 100644 index 0000000..6cbd711 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/3.html @@ -0,0 +1,330 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+    FILE*  stream = stdin;
+    gchar* filename = NULL;
+    GOptionEntry entries[] = {
+	{ "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+	  "file constaining metar observations", NULL },
+	{ NULL }
+    };
+    GOptionContext* context;
+    GError* error = NULL;
+    char buf[BUFLEN];
+    int len;
+    WeatherInfo info;
+
+    context = g_option_context_new ("- test libmateweather metar parser");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    if (filename) {
+	stream = fopen (filename, "r");
+	if (!stream) {
+	    perror ("fopen");
+	    return -1;
+	}
+    } else {
+	fprintf (stderr, "Enter a METAR string...\n");
+    }
+
+    while (fgets (buf, sizeof (buf), stream)) {
+	len = strlen (buf);
+	if (buf[len - 1] == '\n') {
+	    buf[--len] = '\0';
+	}
+	printf ("\n%s\n", buf);
+
+	memset (&info, 0, sizeof (info));
+	info.valid = 1;
+	metar_parse (buf, &info);
+	weather_info_to_metric (&info);
+	printf ("Returned info:\n");
+	printf ("  update:   %s", ctime (&info.update));
+	printf ("  sky:      %s\n", weather_info_get_sky (&info));
+	printf ("  cond:     %s\n", weather_info_get_conditions (&info));
+	printf ("  temp:     %s\n", weather_info_get_temp (&info));
+	printf ("  dewp:     %s\n", weather_info_get_dew (&info));
+	printf ("  wind:     %s\n", weather_info_get_wind (&info));
+	printf ("  pressure: %s\n", weather_info_get_pressure (&info));
+	printf ("  vis:      %s\n", weather_info_get_visibility (&info));
+
+	// TODO: retrieve location's lat/lon to display sunrise/set times
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/4.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/4.html new file mode 100644 index 0000000..7db4465 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/4.html @@ -0,0 +1,350 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+int
+main (int argc, char **argv)
+{
+    WeatherInfo     info;
+    GOptionContext* context;
+    GError*         error = NULL;
+    gdouble         latitude, longitude;
+    WeatherLocation location;
+    gchar*          gtime = NULL;
+    GDate           gdate;
+    struct tm       tm;
+    gboolean        bmoon;
+    time_t          phases[4];
+    const GOptionEntry entries[] = {
+	{ "latitude", 0, 0, G_OPTION_ARG_DOUBLE, &latitude,
+	  "observer's latitude in degrees north", NULL },
+	{ "longitude", 0, 0,  G_OPTION_ARG_DOUBLE, &longitude,
+	  "observer's longitude in degrees east", NULL },
+	{ "time", 0, 0, G_OPTION_ARG_STRING, &gtime,
+	  "time in seconds from Unix epoch", NULL },
+	{ NULL }
+    };
+
+    memset(&location, 0, sizeof(WeatherLocation));
+    memset(&info, 0, sizeof(WeatherInfo));
+
+    context = g_option_context_new ("- test libmateweather sun/moon calculations");
+    g_option_context_add_main_entries (context, entries, NULL);
+    g_option_context_parse (context, &argc, &argv, &error);
+
+    if (error) {
+	perror (error->message);
+	return error->code;
+    }
+    else if (latitude < -90. || latitude > 90.) {
+	perror ("invalid latitude: should be [-90 .. 90]");
+	return -1;
+    } else if (longitude < -180. || longitude > 180.) {
+	perror ("invalid longitude: should be [-180 .. 180]");
+	return -1;
+    }
+
+    location.latitude = DEGREES_TO_RADIANS(latitude);
+    location.longitude = DEGREES_TO_RADIANS(longitude);
+    location.latlon_valid = TRUE;
+    info.location = &location;
+    info.valid = TRUE;
+
+    if (gtime != NULL) {
+	//	printf(" gtime=%s\n", gtime);
+	g_date_set_parse(&gdate, gtime);
+	g_date_to_struct_tm(&gdate, &tm);
+	info.update = mktime(&tm);
+    } else {
+	info.update = time(NULL);
+    }
+
+    calc_sun_time(&info, info.update);
+    bmoon = calc_moon(&info);
+
+    printf ("  Latitude %7.3f %c  Longitude %7.3f %c for %s  All times UTC\n",
+	    fabs(latitude), (latitude >= 0. ? 'N' : 'S'),
+	    fabs(longitude), (longitude >= 0. ? 'E' : 'W'),
+	    asctime(gmtime(&info.update)));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+    printf("sunrise:   %s",
+	   (info.sunriseValid ? ctime(&info.sunrise) : "(invalid)\n"));
+    printf("sunset:    %s",
+	   (info.sunsetValid ? ctime(&info.sunset)  : "(invalid)\n"));
+    if (bmoon) {
+	printf("moonphase: %g\n", info.moonphase);
+	printf("moonlat:   %g\n", info.moonlatitude);
+
+	if (calc_moon_phases(&info, phases)) {
+	    printf("    New:   %s", asctime(gmtime(&phases[0])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    1stQ:  %s", asctime(gmtime(&phases[1])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    Full:  %s", asctime(gmtime(&phases[2])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	    printf("    3rdQ:  %s", asctime(gmtime(&phases[3])));<--- Obsolete function 'asctime' called. It is recommended to use 'strftime' instead.
+	}
+    }
+    return 0;
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/5.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/5.html new file mode 100644 index 0000000..b4aa8dd --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/5.html @@ -0,0 +1,336 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-bom.c - Australian Bureau of Meteorology forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static void
+bom_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    char *p, *rp;
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        g_warning ("Failed to get BOM forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+	return;
+    }
+
+    p = strstr (msg->response_body->data, "Forecast for the rest");
+    if (p != NULL) {
+        rp = strstr (p, "The next routine forecast will be issued");
+        if (rp == NULL)
+            info->forecast = g_strdup (p);
+        else
+            info->forecast = g_strndup (p, rp - p);
+    }
+
+    if (info->forecast == NULL)
+        info->forecast = g_strdup (msg->response_body->data);
+
+    g_print ("%s\n",  info->forecast);
+    request_done (info, TRUE);
+}
+
+void
+bom_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+
+    url = g_strdup_printf ("http://www.bom.gov.au/fwo/%s.txt",
+			   loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, bom_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/6.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/6.html new file mode 100644 index 0000000..e9e5a7e --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/6.html @@ -0,0 +1,1122 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-iwin.c - US National Weather Service IWIN forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+/**
+ *  Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ *  This function makes it easier to read.
+ */
+static gchar *
+formatWeatherMsg (gchar *forecast)
+{
+    gchar *ptr = forecast;
+    gchar *startLine = NULL;
+
+    while (0 != *ptr) {
+        if (ptr[0] == '\n' && ptr[1] == '.') {
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
+            if (NULL == startLine) {
+                memmove (forecast, ptr, strlen (ptr) + 1);
+                ptr = forecast;
+                ptr[0] = ' ';
+            }
+            ptr[1] = '\n';
+            ptr += 2;
+            startLine = ptr;
+        } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+            memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
+            startLine[0] = ' ';
+            startLine[1] = '\n';
+            ptr[2] = '\n';
+
+            ptr += 3;
+
+        } else if (ptr[0] == '$' && ptr[1] == '$') {
+            ptr[0] = ptr[1] = ' ';
+
+        } else {
+            ptr++;
+        }
+    }
+
+    return forecast;
+}
+
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+        return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+        return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    GDateTime *dt = g_date_time_new_from_iso8601 ((const char *)val, NULL);
+                                    if (dt != NULL) {
+                                        update_times[count] = g_date_time_to_unix (dt);
+                                        g_date_time_unref (dt);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunriseValid = FALSE;
+                                nfo->sunsetValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+				nfo->session = NULL;
+				nfo->requests_pending = 0;
+				nfo->finish_cb = NULL;
+				nfo->cb_data = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val || !*val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if (val)
+                                        xmlFree (val);
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
+static void
+iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        /* forecast data is not really interesting anyway ;) */
+        g_warning ("Failed to get IWIN forecast data: %d %s\n",
+                   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    if (info->forecast_type == FORECAST_LIST)
+        info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
+        info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
+    request_done (info, TRUE);
+}
+
+/* Get forecast into newly alloc'ed string */
+void
+iwin_start_open (WeatherInfo *info)
+{
+    gchar *url, *state, *zone;
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    loc = info->location;<--- Assignment 'loc=info->location', assigned value is 0
+    g_return_if_fail (loc != NULL);<--- Assuming that condition 'loc!=NULL' is not redundant
+
+    if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))<--- Null pointer dereference
+        return;
+
+    if (info->forecast) {
+        g_free (info->forecast);
+        info->forecast = NULL;
+    }
+
+    free_forecast_list (info);
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            GDateTime *dt;
+            gint year, month, day;
+
+            dt = g_date_time_new_now_local ();
+            g_date_time_get_ymd (dt, &year, &month, &day);
+            g_date_time_unref (dt);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), year, month, day);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+        return;
+    }
+
+    if (loc->zone[0] == ':') {
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
+    } else if (loc->zone[0] == '@') {
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
+    }
+
+    /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+    ** file (the PA stands for the state pennsylvania). The url used wants the state
+    ** as pa, and the zone as lower case paz021.
+    */
+    zone = g_ascii_strdown (loc->zone, -1);
+    state = g_strndup (zone, 2);
+
+    url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
+
+    g_free (zone);
+    g_free (state);
+
+    msg = soup_message_new ("GET", url);
+    g_free (url);
+    soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/7.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/7.html new file mode 100644 index 0000000..4003099 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/7.html @@ -0,0 +1,528 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-met.c - UK Met Office forecast source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+static char *
+met_reprocess (char *x, int len)
+{
+    char *p = x;
+    char *o;
+    int spacing = 0;
+    static gchar *buf;
+    static gint buflen = 0;
+    gchar *lastspace = NULL;
+    int count = 0;
+
+    if (buflen < len)
+    {
+	if (buf)
+	    g_free (buf);
+	buf = g_malloc (len + 1);
+	buflen = len;
+    }
+
+    o = buf;
+    x += len;       /* End mark */
+
+    while (*p && p < x) {
+	if (g_ascii_isspace (*p)) {
+	    if (!spacing) {
+		spacing = 1;
+		lastspace = o;
+		count++;
+		*o++ = ' ';
+	    }
+	    p++;
+	    continue;
+	}
+	spacing = 0;
+	if (count > 75 && lastspace) {
+	    count = o - lastspace - 1;
+	    *lastspace = '\n';
+	    lastspace = NULL;
+	}
+
+	if (*p == '&') {
+	    if (g_ascii_strncasecmp (p, "&amp;", 5) == 0) {
+		*o++ = '&';
+		count++;
+		p += 5;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&lt;", 4) == 0) {
+		*o++ = '<';
+		count++;
+		p += 4;
+		continue;
+	    }
+	    if (g_ascii_strncasecmp (p, "&gt;", 4) == 0) {
+		*o++ = '>';
+		count++;
+		p += 4;
+		continue;
+	    }
+	}
+	if (*p == '<') {
+	    if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) {
+		*o++ = '\n';
+		count = 0;
+	    }
+	    if (g_ascii_strncasecmp (p, "<B>", 3) == 0) {
+		*o++ = '\n';
+		*o++ = '\n';
+		count = 0;
+	    }
+	    p++;
+	    while (*p && *p != '>')
+		p++;
+	    if (*p)
+		p++;
+	    continue;
+	}
+	*o++ = *p++;
+	count++;
+    }
+    *o = 0;
+    return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For mate 3.0 we want to just embed an HTML matecomponent component and
+ * be done with this ;)
+ */
+
+static gchar *
+met_parse (const gchar *meto)
+{
+    gchar *p;
+    gchar *rp;
+    gchar *r = g_strdup ("Met Office Forecast\n");
+    gchar *t;
+
+    g_return_val_if_fail (meto != NULL, r);
+
+    p = strstr (meto, "Summary: </b>");<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0<--- Assignment 'p=strstr(meto,"Summary: ")', assigned value is 0
+    g_return_val_if_fail (p != NULL, r);<--- Assuming that condition 'p!=NULL' is not redundant<--- Assuming that condition 'p!=NULL' is not redundant
+
+    rp = strstr (p, "Text issued at:");<--- Null pointer dereference
+    g_return_val_if_fail (rp != NULL, r);
+
+    p += 13;<--- Null pointer addition
+    /* p to rp is the text block we want but in HTML malformat */
+    t = g_strconcat (r, met_reprocess (p, rp - p), NULL);
+    g_free (r);
+
+    return t;
+}
+
+static void
+met_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+	g_warning ("Failed to get Met Office forecast data: %d %s.\n",
+		   msg->status_code, msg->reason_phrase);
+        request_done (info, FALSE);
+        return;
+    }
+
+    info->forecast = met_parse (msg->response_body->data);
+    request_done (info, TRUE);
+}
+
+void
+metoffice_start_open (WeatherInfo *info)
+{
+    gchar *url;
+    SoupMessage *msg;
+    WeatherLocation *loc;
+
+    loc = info->location;
+    url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1);
+
+    msg = soup_message_new ("GET", url);
+    soup_session_queue_message (info->session, msg, met_finish, info);
+    g_free (url);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/8.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/8.html new file mode 100644 index 0000000..920b84e --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/8.html @@ -0,0 +1,1324 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-metar.c - Weather server functions (METAR)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather.h"
+#include "weather-priv.h"
+
+enum {
+    TIME_RE,
+    WIND_RE,
+    VIS_RE,
+    COND_RE,
+    CLOUD_RE,
+    TEMP_RE,
+    PRES_RE,
+
+    RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t
+make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+    const time_t now = time (NULL);
+    struct tm tm;
+
+    localtime_r (&now, &tm);
+
+    /* If last reading took place just before midnight UTC on the
+     * first, adjust the date downward to allow for the month
+     * change-over.  This ASSUMES that the reading won't be more than
+     * 24 hrs old! */
+    if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+        tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+                         * month. */
+    } else {
+        tm.tm_mday = utcDate;
+    }
+    tm.tm_hour = utcHour;
+    tm.tm_min  = utcMin;
+    tm.tm_sec  = 0;
+
+    /* mktime() assumes value is local, not UTC.  Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+    return tm.tm_gmtoff + mktime (&tm);
+#elif defined HAVE_TIMEZONE
+    return timezone + mktime (&tm);
+#endif
+}
+
+static void
+metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+    gint day, hr, min;
+
+    sscanf (tokp, "%2u%2u%2u", &day, &hr, &min);
+    info->update = make_time (day, hr, min);
+}
+
+static void
+metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+    gchar sdir[4], sspd[4], sgust[4];
+    gint dir, spd = -1;
+    gchar *gustp;
+    size_t glen;
+
+    strncpy (sdir, tokp, 3);
+    sdir[3] = 0;
+    dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir);
+
+    memset (sspd, 0, sizeof (sspd));
+    glen = strspn (tokp + 3, CONST_DIGITS);
+    strncpy (sspd, tokp + 3, glen);
+    spd = atoi (sspd);
+    tokp += glen + 3;
+
+    gustp = strchr (tokp, 'G');
+    if (gustp) {
+        memset (sgust, 0, sizeof (sgust));
+        glen = strspn (gustp + 1, CONST_DIGITS);
+        strncpy (sgust, gustp + 1, glen);
+        tokp = gustp + 1 + glen;
+    }
+
+    if (!strcmp (tokp, "MPS"))
+        info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd);
+    else
+        info->windspeed = (WeatherWindSpeed)spd;
+
+    if ((349 <= dir) || (dir <= 11))<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))
+        info->wind = WIND_NNE;
+    else if ((34 <= dir) && (dir <= 56))
+        info->wind = WIND_NE;
+    else if ((57 <= dir) && (dir <= 78))
+        info->wind = WIND_ENE;
+    else if ((79 <= dir) && (dir <= 101))
+        info->wind = WIND_E;
+    else if ((102 <= dir) && (dir <= 123))
+        info->wind = WIND_ESE;
+    else if ((124 <= dir) && (dir <= 146))
+        info->wind = WIND_SE;
+    else if ((147 <= dir) && (dir <= 168))
+        info->wind = WIND_SSE;
+    else if ((169 <= dir) && (dir <= 191))
+        info->wind = WIND_S;
+    else if ((192 <= dir) && (dir <= 213))
+        info->wind = WIND_SSW;
+    else if ((214 <= dir) && (dir <= 236))
+        info->wind = WIND_SW;
+    else if ((237 <= dir) && (dir <= 258))
+        info->wind = WIND_WSW;
+    else if ((259 <= dir) && (dir <= 281))
+        info->wind = WIND_W;
+    else if ((282 <= dir) && (dir <= 303))
+        info->wind = WIND_WNW;
+    else if ((304 <= dir) && (dir <= 326))
+        info->wind = WIND_NW;
+    else if ((327 <= dir) && (dir <= 348))<--- Condition 'dir<=348' is always true
+        info->wind = WIND_NNW;
+}
+
+static void
+metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+    gchar *pfrac, *pend, *psp;
+    gchar sval[6];
+    gint num, den, val;
+
+    memset (sval, 0, sizeof (sval));
+
+    if (!strcmp (tokp,"CAVOK")) {
+        // "Ceiling And Visibility OK": visibility >= 10 KM
+        info->visibility=10000. / VISIBILITY_SM_TO_M (1.);
+        info->sky = SKY_CLEAR;
+    } else if (0 != (pend = strstr (tokp, "SM"))) {
+        // US observation: field ends with "SM"
+        pfrac = strchr (tokp, '/');
+        if (pfrac) {
+            if (*tokp == 'M') {
+                info->visibility = 0.001;
+            } else {
+                num = (*(pfrac - 1) - '0');
+                strncpy (sval, pfrac + 1, pend - pfrac - 1);
+                den = atoi (sval);
+                info->visibility =
+                    ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+                psp = strchr (tokp, ' ');
+                if (psp) {
+                    *psp = '\0';
+                    val = atoi (tokp);
+                    info->visibility += (WeatherVisibility)val;
+                }
+            }
+        } else {
+            strncpy (sval, tokp, pend - tokp);
+            val = atoi (sval);
+            info->visibility = (WeatherVisibility)val;
+        }
+    } else {
+        // International observation: NNNN(DD NNNNDD)?
+        // For now: use only the minimum visibility and ignore its direction
+        strncpy (sval, tokp, strspn (tokp, CONST_DIGITS));
+        val = atoi (sval);
+        info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.);
+    }
+}
+
+static void
+metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+    gchar stype[4], salt[4];
+
+    strncpy (stype, tokp, 3);
+    stype[3] = 0;
+    if (strlen (tokp) == 6) {
+        strncpy (salt, tokp + 3, 3);
+        salt[3] = 0;
+    }
+
+    if (!strcmp (stype, "CLR")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "SKC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "NSC")) {
+        info->sky = SKY_CLEAR;
+    } else if (!strcmp (stype, "BKN")) {
+        info->sky = SKY_BROKEN;
+    } else if (!strcmp (stype, "SCT")) {
+        info->sky = SKY_SCATTERED;
+    } else if (!strcmp (stype, "FEW")) {
+        info->sky = SKY_FEW;
+    } else if (!strcmp (stype, "OVC")) {
+        info->sky = SKY_OVERCAST;
+    }
+}
+
+static void
+metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+    if (*tokp == 'A') {
+        gchar sintg[3], sfract[3];
+        gint intg, fract;
+
+        strncpy (sintg, tokp + 1, 2);
+        sintg[2] = 0;
+        intg = atoi (sintg);
+
+        strncpy (sfract, tokp + 3, 2);
+        sfract[2] = 0;
+        fract = atoi (sfract);
+
+        info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+    } else {  /* *tokp == 'Q' */
+        gchar spres[5];
+        gint pres;
+
+        strncpy (spres, tokp + 1, 4);
+        spres[4] = 0;
+        pres = atoi (spres);
+
+        info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres);
+    }
+}
+
+static void
+metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+    gchar *ptemp, *pdew, *psep;
+
+    psep = strchr (tokp, '/');
+    *psep = 0;
+    ptemp = tokp;
+    pdew = psep + 1;
+
+    info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))
+        : TEMP_C_TO_F (atoi (ptemp));
+    if (*pdew) {
+        info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))
+            : TEMP_C_TO_F (atoi (pdew));
+    } else {
+        info->dew = -1000.0;
+    }
+}
+
+static void
+metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+    gchar squal[3], sphen[4];
+    gchar *pphen;
+
+    if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+        ++tokp;   /* FIX */
+
+    if ((*tokp == '+') || (*tokp == '-'))
+        pphen = tokp + 1;
+    else if (strlen (tokp) < 4)
+        pphen = tokp;
+    else
+        pphen = tokp + 2;
+
+    memset (squal, 0, sizeof (squal));
+    strncpy (squal, tokp, pphen - tokp);
+    squal[pphen - tokp] = 0;
+
+    memset (sphen, 0, sizeof (sphen));
+    strncpy (sphen, pphen, sizeof (sphen));
+    sphen[sizeof (sphen)-1] = '\0';
+
+    /* Defaults */
+    info->cond.qualifier = QUALIFIER_NONE;
+    info->cond.phenomenon = PHENOMENON_NONE;
+    info->cond.significant = FALSE;
+
+    if (!strcmp (squal, "")) {
+        info->cond.qualifier = QUALIFIER_MODERATE;
+    } else if (!strcmp (squal, "-")) {
+        info->cond.qualifier = QUALIFIER_LIGHT;
+    } else if (!strcmp (squal, "+")) {
+        info->cond.qualifier = QUALIFIER_HEAVY;
+    } else if (!strcmp (squal, "VC")) {
+        info->cond.qualifier = QUALIFIER_VICINITY;
+    } else if (!strcmp (squal, "MI")) {
+        info->cond.qualifier = QUALIFIER_SHALLOW;
+    } else if (!strcmp (squal, "BC")) {
+        info->cond.qualifier = QUALIFIER_PATCHES;
+    } else if (!strcmp (squal, "PR")) {
+        info->cond.qualifier = QUALIFIER_PARTIAL;
+    } else if (!strcmp (squal, "TS")) {
+        info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+    } else if (!strcmp (squal, "BL")) {
+        info->cond.qualifier = QUALIFIER_BLOWING;
+    } else if (!strcmp (squal, "SH")) {
+        info->cond.qualifier = QUALIFIER_SHOWERS;
+    } else if (!strcmp (squal, "DR")) {
+        info->cond.qualifier = QUALIFIER_DRIFTING;
+    } else if (!strcmp (squal, "FZ")) {
+        info->cond.qualifier = QUALIFIER_FREEZING;
+    } else {
+        return;
+    }
+
+    if (!strcmp (sphen, "DZ")) {
+        info->cond.phenomenon = PHENOMENON_DRIZZLE;
+    } else if (!strcmp (sphen, "RA")) {
+        info->cond.phenomenon = PHENOMENON_RAIN;
+    } else if (!strcmp (sphen, "SN")) {
+        info->cond.phenomenon = PHENOMENON_SNOW;
+    } else if (!strcmp (sphen, "SG")) {
+        info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+    } else if (!strcmp (sphen, "IC")) {
+        info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+    } else if (!strcmp (sphen, "PE")) {
+        info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+    } else if (!strcmp (sphen, "GR")) {
+        info->cond.phenomenon = PHENOMENON_HAIL;
+    } else if (!strcmp (sphen, "GS")) {
+        info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+    } else if (!strcmp (sphen, "UP")) {
+        info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+    } else if (!strcmp (sphen, "BR")) {
+        info->cond.phenomenon = PHENOMENON_MIST;
+    } else if (!strcmp (sphen, "FG")) {
+        info->cond.phenomenon = PHENOMENON_FOG;
+    } else if (!strcmp (sphen, "FU")) {
+        info->cond.phenomenon = PHENOMENON_SMOKE;
+    } else if (!strcmp (sphen, "VA")) {
+        info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+    } else if (!strcmp (sphen, "SA")) {
+        info->cond.phenomenon = PHENOMENON_SAND;
+    } else if (!strcmp (sphen, "HZ")) {
+        info->cond.phenomenon = PHENOMENON_HAZE;
+    } else if (!strcmp (sphen, "PY")) {
+        info->cond.phenomenon = PHENOMENON_SPRAY;
+    } else if (!strcmp (sphen, "DU")) {
+        info->cond.phenomenon = PHENOMENON_DUST;
+    } else if (!strcmp (sphen, "SQ")) {
+        info->cond.phenomenon = PHENOMENON_SQUALL;
+    } else if (!strcmp (sphen, "SS")) {
+        info->cond.phenomenon = PHENOMENON_SANDSTORM;
+    } else if (!strcmp (sphen, "DS")) {
+        info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+    } else if (!strcmp (sphen, "PO")) {
+        info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+    } else if (!strcmp (sphen, "+FC")) {
+        info->cond.phenomenon = PHENOMENON_TORNADO;
+    } else if (!strcmp (sphen, "FC")) {
+        info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+    } else {
+        return;
+    }
+
+    if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+        info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR  "([0-9]{6})Z"
+#define WIND_RE_STR  "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)"
+#define VIS_RE_STR   "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+    "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+    "CAVOK"
+#define COND_RE_STR  "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR  "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR  "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ *   (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info);
+
+static void
+metar_init_re (void)
+{
+    static gboolean initialized = FALSE;
+    if (initialized)
+        return;
+    initialized = TRUE;
+
+    regcomp (&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+    regcomp (&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+    metar_f[TIME_RE] = metar_tok_time;
+    metar_f[WIND_RE] = metar_tok_wind;
+    metar_f[VIS_RE] = metar_tok_vis;
+    metar_f[COND_RE] = metar_tok_cond;
+    metar_f[CLOUD_RE] = metar_tok_cloud;
+    metar_f[TEMP_RE] = metar_tok_temp;
+    metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean
+metar_parse (gchar *metar, WeatherInfo *info)
+{
+    gchar *p;
+    //gchar *rmk;
+    gint i, i2;
+    regmatch_t rm, rm2;
+    gchar *tokp;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (metar != NULL, FALSE);
+
+    metar_init_re ();
+
+    /*
+     * Force parsing to end at "RMK" field.  This prevents a subtle
+     * problem when info within the remark happens to match an earlier state
+     * and, as a result, throws off all the remaining expression
+     */
+    if (0 != (p = strstr (metar, " RMK "))) {
+        *p = '\0';
+        //rmk = p + 5;   // uncomment this if RMK data becomes useful
+    }
+
+    p = metar;
+    i = TIME_RE;<--- Variable 'i' is assigned a value that is never used.
+    while (*p) {
+
+        i2 = RE_NUM;
+        rm2.rm_so = strlen (p);
+        rm2.rm_eo = rm2.rm_so;
+
+        for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+            if (0 == regexec (&metar_re[i], p, 1, &rm, 0)
+                && rm.rm_so < rm2.rm_so)
+            {
+                i2 = i;
+                /* Skip leading and trailing space characters, if present.
+                   (the regular expressions include those characters to
+                   only get matches limited to whole words). */
+                if (p[rm.rm_so] == ' ') rm.rm_so++;
+                if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--;
+                rm2.rm_so = rm.rm_so;
+                rm2.rm_eo = rm.rm_eo;
+            }
+        }
+
+        if (i2 != RE_NUM) {
+            tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so);
+            metar_f[i2] (tokp, info);
+            g_free (tokp);
+        }
+
+        p += rm2.rm_eo;
+        p += strspn (p, " ");
+    }
+    return TRUE;
+}
+
+static void
+metar_finish (SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    WeatherInfo *info = (WeatherInfo *)data;
+    WeatherLocation *loc;
+    const gchar *p, *endtag;
+    gchar *searchkey, *metar;
+    gboolean success = FALSE;
+
+    g_return_if_fail (info != NULL);
+
+    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+        if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
+            info->network_error = TRUE;
+        else {
+            /* Translators: %d is an error code, and %s the error string */
+            g_warning (_("Failed to get METAR data: %d %s.\n"),
+                       msg->status_code, msg->reason_phrase);
+        }
+        request_done (info, FALSE);
+        return;
+    }
+
+    loc = info->location;
+
+    searchkey = g_strdup_printf ("<raw_text>%s", loc->code);
+    p = strstr (msg->response_body->data, searchkey);
+    g_free (searchkey);
+    if (p) {
+        p += WEATHER_LOCATION_CODE_LEN + 11;
+        endtag = strstr (p, "</raw_text>");
+        if (endtag)
+            metar = g_strndup (p, endtag - p);
+        else
+            metar = g_strdup (p);
+        success = metar_parse (metar, info);
+        g_free (metar);
+    } else if (!strstr (msg->response_body->data, "aviationweather.gov")) {
+        /* The response doesn't even seem to have come from NOAA...
+         * most likely it is a wifi hotspot login page. Call that a
+         * network error.
+         */
+        info->network_error = TRUE;
+    }
+
+    info->valid = success;
+    request_done (info, TRUE);
+}
+
+/* Read current conditions and fill in info structure */
+void
+metar_start_open (WeatherInfo *info)
+{
+    WeatherLocation *loc;
+    SoupMessage *msg;
+
+    g_return_if_fail (info != NULL);
+    info->valid = info->network_error = FALSE;
+    loc = info->location;
+    if (loc == NULL) {
+        g_warning (_("WeatherInfo missing location"));
+        return;
+    }
+
+    msg = soup_form_request_new (
+        "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam",
+        "dataSource", "metars",
+        "requestType", "retrieve",
+        "format", "xml",
+        "hoursBeforeNow", "3",
+        "mostRecent", "true",
+        "fields", "raw_text",
+        "stationString", loc->code,
+        NULL);
+    soup_session_queue_message (info->session, msg, metar_finish, info);
+
+    info->requests_pending++;
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/9.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/9.html new file mode 100644 index 0000000..32212e4 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/9.html @@ -0,0 +1,876 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* weather-sun.c - Astronomy calculations for mateweather
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ * Unless otherwise noted, comments referencing "steps" are related to
+ * the algorithm presented in section 49 of above
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "weather-priv.h"
+
+#define ECCENTRICITY(d)         (0.01671123 - (d)/36525.*0.00004392)
+
+/*
+ * Ecliptic longitude of the sun at specified time (UT)
+ * The algoithm is described in section 47 of Duffett-Smith
+ * Return value is in radians
+ */
+gdouble
+sunEclipLongitude(time_t t)
+{
+    gdouble ndays, meanAnom, eccenAnom, delta, e, longitude;
+
+    /*
+     * Start with an estimate based on a fixed daily rate
+     */
+    ndays = EPOCH_TO_J2000(t) / 86400.;
+    meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)
+				  - PERIGEE_LONGITUDE(ndays));
+
+    /*
+     * Approximate solution of Kepler's equation:
+     * Find E which satisfies  E - e sin(E) = M (mean anomaly)
+     */
+    eccenAnom = meanAnom;
+    e = ECCENTRICITY(ndays);
+
+    while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom))
+    {
+	eccenAnom -= delta / (1.- e * cos(eccenAnom));
+    }
+
+    /*
+     * Earth's longitude on the ecliptic
+     */
+    longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))
+		      + 2. * atan (sqrt ((1.+e)/(1.-e))
+				   * tan (eccenAnom / 2.)),
+		      2. * M_PI);
+    if (longitude < 0.) {
+	longitude += 2 * M_PI;
+    }
+    return longitude;
+}
+
+static gdouble
+ecliptic_obliquity (gdouble time)
+{
+    gdouble jc = EPOCH_TO_J2000 (time) / (36525. * 86400.);
+    gdouble eclip_secs = (84381.448
+			  - (46.84024 * jc)
+			  - (59.e-5 * jc * jc)
+			  + (1.813e-3 * jc * jc * jc));
+    return DEGREES_TO_RADIANS(eclip_secs / 3600.);
+}
+
+/*
+ * Convert ecliptic longitude and latitude (radians) to equitorial
+ * coordinates, expressed as right ascension (hours) and
+ * declination (radians)
+ */
+void
+ecl2equ (gdouble time,
+	 gdouble eclipLon, gdouble eclipLat,
+	 gdouble *ra, gdouble *decl)
+{
+    gdouble mEclipObliq = ecliptic_obliquity(time);
+
+    if (ra) {
+	*ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)
+					- tan (eclipLat) * sin(mEclipObliq)),
+				       cos (eclipLon)));
+	if (*ra < 0.)
+	    *ra += 24.;
+    }
+    if (decl) {
+	*decl = asin (( sin (eclipLat) * cos (mEclipObliq))
+		      + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon));
+    }
+}
+
+/*
+ * Calculate rising and setting times for an object
+ * based on it equitorial coordinates (section 33 & 15)
+ * Returned "rise" and "set" values are sideral times in hours
+ */
+static void
+gstObsv (gdouble ra, gdouble decl,
+	 gdouble obsLat, gdouble obsLon,
+	 gdouble *rise, gdouble *set)
+{
+    double a = acos (-tan (obsLat) * tan (decl));
+    double b;
+
+    if (isnan (a) != 0) {
+	*set = *rise = a;
+	return;
+    }
+    a = RADIANS_TO_HOURS (a);
+    b = 24. - a + ra;
+    a += ra;
+    a -= RADIANS_TO_HOURS (obsLon);
+    b -= RADIANS_TO_HOURS (obsLon);
+    if ((a = fmod (a, 24.)) < 0)
+	a += 24.;
+    if ((b = fmod (b, 24.)) < 0)
+	b += 24.;
+
+    *set = a;
+    *rise = b;
+}
+
+
+static gdouble
+t0 (time_t date)
+{
+    gdouble t = ((gdouble)(EPOCH_TO_J2000 (date) / 86400)) / 36525.0;
+    gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+    if (t0 < 0.)
+        t0 += 24.;
+    return t0;
+}
+
+
+static gboolean
+calc_sun2 (WeatherInfo *info, time_t t)
+{
+    gdouble obsLat = info->location->latitude;<--- obsLat is initialized
+    gdouble obsLon = info->location->longitude;<--- obsLon is initialized
+    time_t gm_midn;
+    time_t lcl_midn;
+    gdouble gm_hoff, lambda;
+    gdouble ra1, ra2;
+    gdouble decl1, decl2;
+    gdouble decl_midn, decl_noon;
+    gdouble rise1, rise2;
+    gdouble set1, set2;
+    gdouble tt, t00;
+    gdouble x, u, dt;
+
+    /* Approximate preceding local midnight at observer's longitude */
+    obsLat = info->location->latitude;<--- obsLat is overwritten
+    obsLon = info->location->longitude;<--- obsLon is overwritten
+    gm_midn = t - (t % 86400);
+    gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon) + 7.5) / 15.);
+    lcl_midn = gm_midn - 3600. * gm_hoff;
+    if (t - lcl_midn >= 86400)
+        lcl_midn += 86400;
+    else if (lcl_midn > t)
+        lcl_midn -= 86400;
+
+    lambda = sunEclipLongitude (lcl_midn);
+
+    /*
+     * Calculate equitorial coordinates of sun at previous
+     * and next local midnights
+     */
+    ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1);
+    ecl2equ (lcl_midn + 86400.,
+	     lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), 0.,
+	     &ra2, &decl2);
+
+    /*
+     * If the observer is within the Arctic or Antarctic Circles then
+     * the sun may be above or below the horizon for the full day.
+     */
+    decl_midn = MIN(decl1,decl2);
+    decl_noon = (decl1+decl2)/2.;
+    info->midnightSun =
+	(obsLat > (M_PI/2.-decl_midn)) || (obsLat < (-M_PI/2.-decl_midn));
+    info->polarNight =
+	(obsLat > (M_PI/2.+decl_noon)) || (obsLat < (-M_PI/2.+decl_noon));
+    if (info->midnightSun || info->polarNight) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+	return FALSE;
+    }
+
+    /*
+     * Convert to rise and set times based positions for the preceding
+     * and following local midnights.
+     */
+    gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+    gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+    /* TODO: include calculations for regions near the poles. */
+    if (isnan(rise1) || isnan(rise2)) {
+	info->sunriseValid = info->sunsetValid = FALSE;
+        return FALSE;
+    }
+
+    if (rise2 < rise1) {
+        rise2 += 24.;
+    }
+    if (set2 < set1) {
+        set2 += 24.;
+    }
+
+    tt = t0(lcl_midn);
+    t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+    if (t00 < 0.)
+        t00 += 24.;
+
+    if (rise1 < t00) {
+        rise1 += 24.;
+        rise2 += 24.;
+    }
+    if (set1 < t00) {
+        set1  += 24.;
+        set2  += 24.;
+    }
+
+    /*
+     * Interpolate between the two to get a rise and set time
+     * based on the sun's position at local noon (step 8)
+     */
+    rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+    set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+    /*
+     * Calculate an adjustment value to account for parallax,
+     * refraction and the Sun's finite diameter (steps 9,10)
+     */
+    decl2 = (decl1 + decl2) / 2.;
+    x = DEGREES_TO_RADIANS(0.830725);
+    u = acos ( sin(obsLat) / cos(decl2) );
+    dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) );
+
+    /*
+     * Subtract the correction value from sunrise and add to sunset,
+     * then (step 11) convert sideral times to UT
+     */
+    rise1 = (rise1 - dt - tt) * 0.9972695661;
+    if (rise1 < 0.)
+	rise1 += 24;
+    else if (rise1 >= 24.)
+	rise1 -= 24.;
+    info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.));
+    info->sunrise = (rise1 * 3600.) + lcl_midn;
+
+    set1  = (set1 + dt - tt) * 0.9972695661;
+    if (set1 < 0.)
+	set1 += 24;
+    else if (set1 >= 24.)
+	set1 -= 24.;
+    info->sunsetValid = ((set1 >= 0.) && (set1 < 24.));
+    info->sunset = (set1 * 3600.) + lcl_midn;
+
+    return (info->sunriseValid || info->sunsetValid);
+}
+
+
+/**
+ * calc_sun_time:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ * @t: time_t
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun_time (WeatherInfo *info, time_t t)
+{
+    return info->location->latlon_valid && calc_sun2 (info, t);
+}
+
+/**
+ * calc_sun:
+ * @info: #WeatherInfo structure containing the observer's latitude
+ * and longitude in radians, fills in the sunrise and sunset times.
+ *
+ * Returns: gboolean indicating if the results are valid.
+ */
+gboolean
+calc_sun (WeatherInfo *info)
+{
+    return calc_sun_time(info, time(NULL));
+}
+
+
+/**
+ * weather_info_next_sun_event:
+ * @info: #WeatherInfo structure
+ *
+ * Returns: the interval, in seconds, until the next "sun event":
+ *  - local midnight, when rise and set times are recomputed
+ *  - next sunrise, when icon changes to daytime version
+ *  - next sunset, when icon changes to nighttime version
+ */
+gint
+weather_info_next_sun_event (WeatherInfo *info)
+{
+    time_t    now = time (NULL);
+    struct tm ltm;
+    time_t    nxtEvent;
+
+    g_return_val_if_fail (info != NULL, -1);
+
+    if (!calc_sun (info))
+	return -1;
+
+    /* Determine when the next local midnight occurs */
+    (void) localtime_r (&now, &ltm);
+    ltm.tm_sec = 0;
+    ltm.tm_min = 0;
+    ltm.tm_hour = 0;
+    ltm.tm_mday++;
+    nxtEvent = mktime (&ltm);
+
+    if (info->sunsetValid &&
+	(info->sunset > now) && (info->sunset < nxtEvent))
+	nxtEvent = info->sunset;
+    if (info->sunriseValid &&
+	(info->sunrise > now) && (info->sunrise < nxtEvent))
+	nxtEvent = info->sunrise;
+    return (gint)(nxtEvent - now);
+}
+
+
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/index.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/index.html new file mode 100644 index 0000000..7d0d538 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/index.html @@ -0,0 +1,165 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineIdCWESeverityMessage
missingIncludeinformationCppcheck cannot find all the include files (use --check-config for details)
libmateweather/location-entry.c
303variableScope398styleThe scope of the variable 'cmpcode' can be reduced.
libmateweather/mateweather-timezone.c
71variableScope398styleThe scope of the variable 'second_isdst' can be reduced.
libmateweather/parser.c
94variableScope398styleThe scope of the variable 'next_tagname' can be reduced.
117arrayIndexThenCheck398styleArray index 'i' is used before limits check.
libmateweather/test_metar.c
29variableScope398styleThe scope of the variable 'len' can be reduced.
libmateweather/test_sun_moon.c
73asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
83asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
84asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
85asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
86asctimeCalled477styleObsolete function 'asctime' called. It is recommended to use 'strftime' instead.
libmateweather/weather-bom.c
32variableScope398styleThe scope of the variable 'rp' can be reduced.
libmateweather/weather-iwin.c
417nullPointerRedundantCheck476warningEither the condition 'loc!=NULL' is redundant or there is possible null pointer dereference: loc.
libmateweather/weather-met.c
135nullPointerRedundantCheck476warningEither the condition 'p!=NULL' is redundant or there is possible null pointer dereference: p.
138nullPointerArithmeticRedundantCheck682warningEither the condition 'p!=NULL' is redundant or there is pointer arithmetic with NULL pointer.
libmateweather/weather-metar.c
145knownConditionTrueFalse571styleCondition 'dir<=348' is always true
454unreadVariable563styleVariable 'i' is assigned a value that is never used.
493variableScope398styleThe scope of the variable 'endtag' can be reduced.
494variableScope398styleThe scope of the variable 'metar' can be reduced.
libmateweather/weather-sun.c
178redundantInitialization563styleRedundant initialization for 'obsLat'. The initialized value is overwritten before it is read.
179redundantInitialization563styleRedundant initialization for 'obsLon'. The initialized value is overwritten before it is read.
libmateweather/weather-wx.c
64nullPointerRedundantCheck476warningEither the condition 'info!=NULL' is redundant or there is possible null pointer dereference: info.
libmateweather/weather.c
326variableScope398styleThe scope of the variable 'str' can be reduced.
498uselessAssignmentPtrArg398warningAssignment of function parameter has no effect outside the function. Did you forget dereferencing it?
498unreadVariable563styleVariable 'location' is assigned a value that is never used.
700variableScope398styleThe scope of the variable 'utf8' can be reduced.
700variableScope398styleThe scope of the variable 'timeformat' can be reduced.
718unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1073unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1094unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/stats.html b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/stats.html new file mode 100644 index 0000000..bb7d58a --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/stats.html @@ -0,0 +1,119 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 5
+   2  libmateweather/weather-met.c
+   1  libmateweather/weather.c
+   1  libmateweather/weather-wx.c
+   1  libmateweather/weather-iwin.c
+

+

Top 10 files for style severity, total findings: 24
+   7  libmateweather/weather.c
+   5  libmateweather/test_sun_moon.c
+   4  libmateweather/weather-metar.c
+   2  libmateweather/weather-sun.c
+   2  libmateweather/parser.c
+   1  libmateweather/weather-bom.c
+   1  libmateweather/test_metar.c
+   1  libmateweather/mateweather-timezone.c
+   1  libmateweather/location-entry.c
+

+ +
+
+ + + diff --git a/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/style.css b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2020-12-10-200446-1523-cppcheck@93dbf10c7ea2_master/style.css @@ -0,0 +1,137 @@ + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 13px; + line-height: 1.5; + margin: 0; + width: auto; +} + +h1 { + margin: 10px; +} + +.header { + border-bottom: thin solid #aaa; +} + +.footer { + border-top: thin solid #aaa; + font-size: 90%; + margin-top: 5px; +} + +.footer ul { + list-style-type: none; + padding-left: 0; +} + +.footer > p { + margin: 4px; +} + +.wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +#menu, +#menu_index { + text-align: left; + width: 350px; + height: 90vh; + min-height: 200px; + overflow: auto; + position: -webkit-sticky; + position: sticky; + top: 0; + padding: 0 15px 15px 15px; +} + +#menu > a { + display: block; + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +#content, +#content_index { + background-color: #fff; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding: 0 15px 15px 15px; + width: calc(100% - 350px); + height: 100%; + overflow-x: auto; +} + +#filename { + margin-left: 10px; + font-size: 12px; + z-index: 1; +} + +.error { + background-color: #ffb7b7; +} + +.error2 { + background-color: #faa; + display: inline-block; + margin-left: 4px; +} + +.inconclusive { + background-color: #b6b6b4; +} + +.inconclusive2 { + background-color: #b6b6b4; + display: inline-block; + margin-left: 4px; +} + +.verbose { + display: inline-block; + vertical-align: top; + cursor: help; +} + +.verbose .content { + display: none; + position: absolute; + padding: 10px; + margin: 4px; + max-width: 40%; + white-space: pre-wrap; + border: 1px solid #000; + background-color: #ffffcc; + cursor: auto; +} + +.highlight .hll { + padding: 1px; +} + +.highlighttable { + background-color: #fff; + z-index: 10; + position: relative; + margin: -10px; +} + +.linenos { + border-right: thin solid #aaa; + color: #d3d3d3; + padding-right: 6px; +} + +.d-none { + display: none; +} diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..18ed0fc --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +libmateweather.mate-desktop.dev diff --git a/index.html b/index.html new file mode 100644 index 0000000..b4846e3 --- /dev/null +++ b/index.html @@ -0,0 +1,46 @@ + + + + + libmateweather Code Analyzer results + + +

+ mate-desktop/libmateweather Static analyzer results +

+ GitHub + Build Status +
+Commit: 93dbf10c7ea2af587eb0420796b654b12deca250
+Compare: 6489fd5efa22...93dbf10c7ea2
+Branch: master
+Time: 2020-12-10 20:04:46+00:00
+Messages:
+
+Install icons in fallback icon theme
+
+
+ + + -- cgit v1.2.1